1. 程式人生 > 實用技巧 >Vue watch監聽器 computed計算屬性 filter過濾器 過渡動畫

Vue watch監聽器 computed計算屬性 filter過濾器 過渡動畫

1-watch偵聽器(監聽器)

  • 本質: 一個特殊的函式

  • 作用: 監視data中任意一個數據的改變, 從而實現一些特殊的業務處理

  • 注意:

    • 監視器函式的名字必須和要被監視的資料名稱保持一致
    • 無需手動呼叫
  • 語法

    const vm = new Vue({
        el: '#app',
        data: {
            msg:'hello',
            user:{
                name:'zs',
                age:20,
                sex:'男'
            }
        },
        methods: {
            updateMsg(){
                this.msg='你好';
            },
            updateUser(){
                this.user.name='張三';
                // this.user={name:'張三'};
            }
        },
        // watch監聽器
        watch:{
            // 監視器函式的名字必須和監視的資料名保持一致
            msg(newVal,oldVal){
                console.log(newVal,oldVal);
            },
            // 更新物件中某一個屬性的時候, 普通的監視器監聽不到屬性更新, 必須使用深度監聽
            // 深度監聽
            user:{
                // 監聽方法
                handler(newVal,oldVal){
                    console.log(newVal,oldVal);
                },
                // true表示要開啟深度監聽
                deep:true
            }
        }
    });
    

2-computed計算屬性

  • 本質: 一種特殊的函式(當做資料呼叫)

  • 作用: 可以根據已經存在的資料, 計算出來一個不存在的資料

  • 注意:

    • computed計算屬性函式必須有返回值
    • 計算屬性函式名不能和data中的資料同名
    • 呼叫的時候, 當做變數直接呼叫, 無需帶()
  • 特點: 計算屬性內部會有一些快取機制

  • 語法

    <!--呼叫計算屬性--> 
    <h1>{{fullName}}</h1>
    
     const vm = new Vue({
         el: '#app',
         data: {
             firstName: '',
             lastName: '',
         },
         methods: {
             // 根據fistname和lastname計算一個fullname
             fname(){
                 console.log('普通方法');
                 return this.firstName+this.lastName;   
             }
         },
         // computed計算屬性
         computed:{
             // 定義計算屬性
             fullName:function(){
                 console.log('計算屬性方法');
                 return this.firstName+this.lastName;
             }
         }
     });
    

3-filter過濾器

  • 本質: 一種特殊的方法

  • 作用: 對資料進行預處理

  • 注意

    • 過濾器處理函式必須至少有一個引數, 第一個引數永遠是待處理的資料, 由系統自動注入
    • 過濾器處理函式必須有返回值
    • 過濾器只能在插值表示式和v-bind指令中使用(其他指令中使用會報錯)
  • 呼叫格式: 資料輸出的位置

    {{msg | fn}}
    

3.1-全域性過濾器

  • 特點: 在所有的vue例項中都可以呼叫

  • 語法格式

    Vue.filter('過濾器的名稱',functoin(){  //進行資料預處理的函式  });
    
  • 呼叫全域性過濾器

    <div id="app">
       <!-- 呼叫過濾器 -->
       <h1>{{msg | append}}</h1>
       <hr>
       <h1>{{msg | append1('***')}}</h1>
       <hr>
       <!-- 呼叫多個過濾器 -->
       <h1>{{msg | append | append1('####')}}</h1>
    </div>
    
  • 定義全域性過濾器

    // params:系統自動注入的, input代表即將被處理的資料; params額外引數
    Vue.filter('append', function (input) {
    // 必須有返回值
      return input+'~~~';
    });
    Vue.filter('append1', function (input,params) {
    // 必須有返回值
      return input + params;
    });
    
  ### 3.2-私有過濾器

- 特點: 只能在當前vue例項中呼叫

- 書寫位置

  ```js
  new Vue({
      el:'#app',
      // 私有過濾器
      filters:{
          // input:系統自動注入, 代表待處理的資料
          fn(input){
          	// 必須有返回值 
          	return ''
      	}
      }
  });
  • 呼叫私有過濾器

    <div id="app">
          <!-- 呼叫私有過濾器 -->
          <h1>{{msg | append}}</h1>
          <hr>
          <h1>{{msg | append('***')}}</h1>
          <hr>
          <h1>{{createTime | dateFmt}}</h1>
          <h1>{{createTime | dateFmt('/')}}</h1>
          <h1>{{createTime | dateFmt('.')}}</h1>
          <h1>{{createTime | dateFmt('~')}}</h1>
    </div>
    
  • 定義私有過濾器

    const vm = new Vue({
            el: '#app',
            data: {
                msg: 'hello',
                createTime:Date.now()
            },
            // 私有過濾器
            filters:{
                append(input,params='~~~'){
                    return `${input}${params}`
                },
                // 13位毫秒值=>yyyy-mm-dd HH:mm:ss
                dateFmt(input,divider='-'){
                    // input: 時間戳: 13毫秒值
                    // 建立對應的日期物件
                    const date=new Date(input);
                    // 獲取年份
                    const y=date.getFullYear();
                    const m=date.getMonth()+1;
                    const d=date.getDate();
                    const h=date.getHours();
                    const mm=date.getMinutes();
                    const s=date.getSeconds();
                    return `${y}${divider}${m}${divider}${d} ${h}:${mm}:${s}`;
    
                }
            }
        });
    

4-單元素過渡動畫

4.1-自定義過渡動畫類名

4.1.1-實現步驟

  1. 使用<transition></transition>標籤包裹目標元素

     <!-- 第一步: -->
    <transition>
        <h1 v-show="isShow">{{msg}}</h1>
    </transition>
    
  2. 自定義過渡動畫類名的屬性

    /* 第二步: 定義過渡動畫類名對應的屬性 */
    /* 進入階段,離開階段 */
    /* 進入前,離開後 */
    .v-enter,.v-leave-to{
        left:-400px;
    }
    /* 進入中,離開中 */
    .v-enter-active,.v-leave-active{
        position: relative;
        transition: left 1s;
    }
    /* 進入後,離開前 */
    .v-enter-to,.v-leave{
        left:0;
    }
    

4.1.2-自定義過渡類名字首

  • appear: 控制元素以過渡動畫的效果入場
  1. 第一步

     /* 進入前,離開後 */
    .slide-enter,.slide-leave-to{
        left:-400px;
    }
    /* 進入中,離開中 */
    .slide-enter-active,.slide-leave-active{
        position: relative;
        transition: left 1s;
    }
    /* 進入後,離開前 */
    .slide-enter-to,.slide-leave{
        left:0;
    }
    
  2. 第二步

     <!-- appear: 以過渡動畫的方式入場 -->
    <transition appear name="slide">
        <h1 v-show="isShow">{{msg}}</h1>
    </transition>
    

4.2-使用第三方動畫類庫

  1. 下載並引入animate.css

    <!-- 第一步: 引入動畫類庫 -->
    <link rel="stylesheet" href="./libs/[email protected]">
    
  2. 通過屬性引用動畫類名

    • enter-active-class: 指定進入過程中的動畫類名
    • leave-active-class: 指定離開過程中的動畫類名
    <div id="app">
        <!-- 第二步: 通過屬性引用動畫類名; animated是基礎動畫類名, tada是決定動畫方式的類名 -->
        <transition appear enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
            <h1 v-show="isShow">{{msg}}</h1>
        </transition>
        <hr>
        <transition appear enter-active-class="animated swing" leave-active-class="animated wobble">
            <h1 v-show="isShow">{{msg}}</h1>
        </transition>
        <hr>
        <button @click="toggle">切換顯示狀態</button>
    </div>
    

5-列表過渡動畫

5.1-自定義動畫類名

  1. 使用transition-group標籤包裹目標元素(列表元素)

    • tag: 指定最終渲染的標籤名稱
     <!-- tag: 指定transition-group解析時候的標籤 -->
    <transition-group tag="ul" name="slide" appear>
        <li v-for="item in list" :key="item.id">{{item.id}}-{{item.name}}</li>
    </transition-group>
    
  2. 自定義過渡動畫類名

     .slide-enter,.slide-leave-to{
         top:-400px;
    }
    .slide-enter-active,.slide-leave-active{
        position: relative;
        transition: all 1s;
    }
    .slide-enter-to,.slide-leave{
        top:0;
    }
    

5.2-使用第三方動畫類庫

  1. 下載並引入animate動畫類庫

    <!-- 1-引入animate.css -->
    <link rel="stylesheet" href="./libs/[email protected]">
    
  2. 通過屬性引用動畫類名

     <!-- tag: 指定transition-group解析時候的標籤 -->
    <transition-group tag="ul" appear
                      enter-active-class="animated tada"
                      leave-active-class="animated wodder"
                      >
        <li v-for="item in list" :key="item.id">{{item.id}}-{{item.name}}</li>
    </transition-group>
    

5-本地儲存localStorage複習

  • 什麼是localStorage: 瀏覽器端一種資料儲存方案
  • 資料儲存位置: 電腦的磁碟上
  • 儲存資料量: 相對比較大
  • 特點: localStorage中只能儲存字串, 不能直接儲存陣列和物件

相關的方法

  • 讀取資料:

    // 讀取出來的資料型別是字串
    localStorage.getItem('key')
    
  • 寫入資料

    localStorage.setItem('key','value');
    
  • 刪除資料

    localStorage.removeItem('key');
    

6-品牌管理案例

6.1-靜態模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./libs/vue.js"></script>
    <style>
        *{
            padding:0;
            margin:0;
            box-sizing: border-box;
        }
        #app{
            width: 800px;
            margin:20px auto;
        }
        tr{
            height: 50px;
            text-align: center;
        }
        .form-control{
            height: 40px;
            padding:10px;
            width: 100%;
            border:1px solid #DDD;
            border-radius: 4px;
        }
        .btn{
            border:1px solid #DDD;
            width: 60px;
            line-height: 30px;
            text-align: center;
            color:#555;
            background: #EEE;
            border-radius:6px;
            cursor: pointer;
            font-weight: 700;
            outline: 0;
        }
        .active{
            background-color: #EEE;
        }
        table,td{
            border:1px solid #CCC;
            /* 合併邊框 */
            border-collapse: collapse;
        }
        .btn.danger{
            background-color: #D9534F;
            color:#FFF;
        }
        .btn.success{
            background-color:#337AB7;
            color:#FFF;
        }
        .line{
            border-bottom:1px solid #DDD;
            margin:10px 0;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>品牌管理</h1>
        <div class="line"></div>
        <div>
            <input class="form-control" type="text" placeholder="請輸入品牌名稱">
        </div>
        <div class="line"></div>
        <table cellpadding="0" cellspacing="0" width="100%">
            <thead>
                <tr class="active">
                    <td width="120">id</td>
                    <td>品牌名稱</td>
                    <td>新增時間</td>
                    <td>操作</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for="item in 10" :key="item">
                    <td>id</td>
                    <td>品牌名稱-{{item}}</td>
                    <td>2020-11-18 16:23</td>
                    <td>
                        <button class="btn danger">刪除</button>
                        <button class="btn success">編輯</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
<script>
new  Vue({
    el:'#app',
    data:{

    },
    methods:{

    },
    computed:{

    }
});
</script>
</html>

6.2-已實現功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./libs/vue.js"></script>
    <style>
        *{
            padding:0;
            margin:0;
            box-sizing: border-box;
        }
        #app{
            width: 800px;
            margin:20px auto;
        }
        tr{
            height: 50px;
            text-align: center;
        }
        .form-control{
            height: 40px;
            padding:10px;
            width: 100%;
            border:1px solid #DDD;
            border-radius: 4px;
        }
        .btn{
            border:1px solid #DDD;
            width: 60px;
            line-height: 30px;
            text-align: center;
            color:#555;
            background: #EEE;
            border-radius:6px;
            cursor: pointer;
            font-weight: 700;
            outline: 0;
        }
        .active{
            background-color: #EEE;
        }
        table,td{
            border:1px solid #CCC;
            /* 合併邊框 */
            border-collapse: collapse;
        }
        .btn.danger{
            background-color: #D9534F;
            color:#FFF;
        }
        .btn.success{
            background-color:#337AB7;
            color:#FFF;
        }
        .line{
            border-bottom:1px solid #DDD;
            margin:10px 0;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>品牌管理</h1>
        <div class="line"></div>
        <h3>品牌數量:{{brandCount}}</h3>
        <div class="line"></div>
        <div>
            <input @keyup.enter="add" v-model="brandName" class="form-control" type="text" placeholder="請輸入品牌名稱">
        </div>
        <div class="line"></div>
        <table cellpadding="0" cellspacing="0" width="100%">
            <thead>
                <tr class="active">
                    <td width="120">id</td>
                    <td>品牌名稱</td>
                    <td>新增時間</td>
                    <td>操作</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for="item in list" :key="item.id">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.ctime|dateFmt}}</td>
                    <td>
                        <button class="btn danger" @click="del(item.id)">刪除</button>
                        <button class="btn success">編輯</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
<script>
new  Vue({
    el:'#app',
    data:{
        // 和輸入框進行繫結的資料
        brandName:'',
        // 品牌列表陣列
        list:[]
    },
    methods:{
        // 實現品牌新增
        add(){
            // 1-將新增的品牌新增到品牌列表陣列中
            // 1.1-構造品牌物件
            const obj={
                id:this.list.length>0?this.list[0].id+1:1,
                name:this.brandName,
                ctime:Date.now()
            }
            // 1.2-將品牌物件, 新增到陣列中
            this.list.unshift(obj);
            // 1.3-重置表單
            this.brandName='';
            // 2-將品牌列表陣列儲存本地儲存localStorage中
            localStorage.setItem('brandlist',JSON.stringify(this.list));
        },
        // 品牌刪除
        del(id){
            if(!confirm('確認刪除?')){
                return false;
            }
            // 1-刪除頁存記憶體中的資料
            // 通過id查詢index索引
            const index=this.list.findIndex(item=>item.id===id);
            this.list.splice(index,1);
            // 2-刪除本地儲存中的品牌資料
            // 讀取本地儲存中的品牌列表
            // const list=JSON.parse(localStorage.getItem('brandlist')||'[]');
            const list=this.getBrandList();
            // 刪除對應品牌
            list.splice(index,1);
            // 重新寫入
            localStorage.setItem('brandlist',JSON.stringify(list));
        },
        // 從本地儲存中讀取品牌列表
        getBrandList(){
            const list=JSON.parse(localStorage.getItem('brandlist')||'[]');
            return list;
        }
    },
    computed:{
        brandCount(){
            return this.list.length;
        }
    },
    created(){
        // 1-讀取本地儲存中的品牌列表資訊
        // const list=JSON.parse(localStorage.getItem('brandlist')||'[]');
        const list=this.getBrandList();
        // 2-更新資料list
        this.list=list;
    },
    filters:{
        dateFmt(input){
            const date=new Date(input);
            const y=date.getFullYear();
            const m=date.getMonth()+1;
            const d=date.getDate();
            const h=date.getHours();
            const mm=date.getMinutes();
            const s=date.getSeconds();
            return `${y}-${m}-${d} ${h}:${mm}:${s}`;
        }
    }
});
</script>
</html>