Vue 计算属性和监听

260 阅读2分钟

Computed 计算属性

被计算出来的属性就是计算属性,被当做属性来使用

实例1:用户名展示

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

new Vue({
    data:{
        user:{
            email:"shuaige@qq.com",
            nickname:"帅哥",
            phone:"13012341234"
        }
    },
    computed:{
        displayName:{
            get(){
                const user = this.user;
                return user.nickname || user.email || user.phone;  
            },
            set(value){
                this.user.nickname = value;
            }
    },
    
    template:`
     <div>
      {{displayName}}
      <div>
      {{displayName}}
      <button @click="add">set</button>
      </div>
     </div>
    `
    methods:{
        add(){
            this.displayName ='我真帅'
        }
    }
}).$mount("#app");

实例2:列表展示(不用computed写法)

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

let id = 0;
const createUser = (name, gender) =>{
    id += 1;
    return {id: id, name: name, gender: gender};
};
new Vue({
    data(){
        return{
            users:[
                createUser("方方", "男"),
                createUser("圆圆", "女"),
                createUser("小明", "男"),
                createUser("小红", "女")
            ],
            displayUsers:[]
        };
    },
    created(){
        this.displayUsers = this.user;
    },
    methods:{
        showMale(){
            this.displayUsers = this.users.filter(u => u.gender === "男");
        },
        showFemale(){
            this.displayUsers = this.users.filter(u => u.gender === "女");
        },
        showAll(){
            this.displayUsers = this.users;
        }
    },
    template:`
      <div>
        <div>
        <button @click="showAll">全部</button>
        <button @click="showMale">男</button>
        <button @click="showFemale">女</button></div>
        <ul>
          <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.genter}}
        </ul>
      </div>`
}).$mount("#app");

所有的v-for后面必须接一个key
 <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.genter}}

filter 不会修改原数组,得到新数组把地址传给displayUsers

computed写法

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

let id = 0;
const createUser = (name, gender) =>{
    id += 1;
    return {id: id, name: name, gender: gender};
};
new Vue({
    data(){
        return{
            users:[
                createUser("方方", "男"),
                createUser("圆圆", "女"),
                createUser("小明", "男"),
                createUser("小红", "女")
            ],
            gender: ""
        };
    },
    computed:{
        displayUsers(){
            const hash = {
                male: "男",
                female: "女"
            };
            const {user, gender} = this;
            if(gender === ""){
                return users;
            }else if(typeof gender === "string"){
                return users.filter(u => u.gender === hash[gender]);
            }eles{
                throw new Error("gender 的值是意外的值");
            }
        }
    },
    methods:{
        setGender(string){
            this.gender = string;
        }
    },
    template:`
      <div>
        <div>
        <button @click="setGender('')">全部</button>
        <button @click="setGender('male')">男</button>
        <button @click="setGender('female')">女</button></div>
        <ul>
          <li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.genter}}
        </ul>
      </div>`
}).$mount("#app");

缓存
如果依赖的属性没有变化,就不会从新计算
getter和setter 默认不会做缓存,Vue做了特殊处理

watch 监听

当数据变化时,执行一个函数

实例1:撤销

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

new Vue({
    data:{
        n:0,
        history:[],
        inUndoMode:false
    },
    watch:{
        n(newValue, oldValue){
            if(!this.inUndoMode){
                this.history.push({from: oldValue, to: newVlue});
            }
        }
    },
    templaye:`
      <div>
        {{n}}
        <hr />
        <button @click="add1">+1</button>
        <button @click="add2">+2</button>
        <button @click="minus1">-1</button>
        <button @click="minus2">-2</button>
        <hr/>
        <button @click="undo">撤销</button>
        <hr/>
        
        {{history}}
      </div>`
    methods:{
        add1(){
            this.n += 1;
        },
        add2(){
            this.n += 2;
        },
        minus1(){
            this.n -= 1;
        },
        minus2(){
            this.n -=2;
        },
        undo(){
            const last = this.history.pop();
            console.log(last);
            const old = last.from;
            this.inUndoMode = true;
            this.n = old;
            this.$nextTick(()=>{
                this.inUnodMode = false;
            },0)
        }
    }
}).$mount("#app"); 

实例2:模拟computed,但不好用,优先使用computed

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

new Vue({
    data:{
        user:{
            email: "shuaige@qq.com",
            nickname:"帅哥",
            phone:"13012341234"
        },
        displayName:""
    },
    watch:{
        'user.email':{
            handler(){
                const {user: {email, nickname, phone}} = this
                this.displayName = nickname || email || phone
            },
            immediate: true
        },
        'user.phone':{
            handler(){
                const {user: {email, nickname, phone}} = this
                this.displayName = nickname || email || phone
            },
            immediate: true
        },
        'user.nickname':{
            handler(){
                const {user: {email, nickname, phone}} = this
                this.displayName = nickname || email || phone
            },
            immediate: true
        },
    }
    template:`
      <div>
        {{displayName}}
        <button @click="user.nickname=undefined">remove nickname</button>
      </div>
    `,
    methods:{
        changed(){
            console.log(arguments);
            const user = this.user;
            this.displayName = user.nickname || user.email || user.phone;
        }
    }
}).$mount("#app");

match 数据变化

在vue里
如果把简单的数据类型的值变了,那它就变了
如果对象里的简单数据类型的值变了,对象不变,修改的数据变了,只做值的对比
如果一个对象的地址变了,vue才会认为对象变了

obj:{
    handler(){
        console.log('obj 变了')
    },
    deep: true
}
deep(深入进去看)不光比较obj的地址,任何东西都比较,任何东西变了,obj就变了

import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;

new Vue({
    data:{
        n:0,
        obj:{
            a:"a"
        }
    },
    template:`
      <div>
        <button @click="n += 1">n+1</button>
        <button @click="obj.a += 'hi'">obj.a + 'hi'</button>
        <button @click="obj = {a:'a'}">obj = 新对象</button>
    `,
    watch:{
        n(){
            console.log("n 变了");
        },
        obj:{
            handler(){
                console.log("obj 变了");
            },
            deep: true
        },
        "obj.a":function(){
            console.log("obj.n 变了");
        }
    }
}).$mount("#app");

vm.$watch('n', function(){
    console.log('n 变了')
},{immdeiate: true})

watch 语法1

watch 不能使用箭头函数,没有this

new Vue({
    data:n,
    watch:{
         n:()=>{                      //箭头函数没有this
             this.xxx                 //this是window全局的      
             }    
        }
})

watch:{
o2: function(value, oldValue){},             
o3:(){},                          o2的缩写
o4:[f1,f2],                       在o4变化时,按顺序执行f1,f2函数
o5:'methodName',                  去methods里找对应名字的函数
o6:{handler:fn, deep:true, immediate:true},'object.a':function(){}
}

语法2

vm.$watch('xxx', fn, {deep: ..., immediate: ..}

在vue外面使用
或者在vue里使用钩子

creatde(){
    this.$watch('n',function(){
        console.log('n 变了'),
        {immediate: true}
    })
}

computed 和 watch 的区别

computed 和 watch 的区别

commputed计算属性,是用来计算出一个值的,这个值被调用时
(1)不需要加括号,像属性一样
(2)根据依赖自动缓存,如果依赖不变,computed就不用从新计算
watch监听的意思
如果某个属性变化了,就去执行一个函数,有2个选项
(1)immediate 表示第一次渲染时是否执行这个函数
(2)deep 监听一个对象,是否看里面的属性变化

详细资料点击:Vue 计算属性