Computed和Watch的区别

699 阅读2分钟

浅谈一下Vue里computed 和 watch 的区别:

Computed

需求一:data 里给出姓和名,要求展示完整的名字

new Vue({
    data:{
        firstName:'Jack',
        lastName:'Lee'
    },
    computed:{
        fullName(){
            return this.firstName + this.lastName
        }
    },
    template:`
    	<div>
		{{fullName}}
	</div>
	`
}).$mount('#app')

由代码可知:

1.fullName的值是通过 firstName和lastName的值计算而来,所以computed是计算属性;

2.template里调用fullName的值,可以把fullName当成属性直接调用,不用加括号( )

需求二:光看名字还不行,还要能改名字

new Vue({
    data:{
        firstName:'Jack',
        lastName:'Lee'
    },
    computed:{
        fullName:{
            get(){
                return this.firstName + ' ' + this.lastName 
            },
            set(val){
                const names = val.split(' ') 
                this.firstName = names[0]
                this.lastName = names[1]
            }
        }
    },
    template:`
        <div>
		{{fullName}}
		<button @click="change">改名字</button>
	</div>
	`,
    methods:{
        change(){
            this.fullName = 'Tom Chen'
            console.log('名字已更改')
        }
    }
})

这里注意一下区别:

computed:{
    fullName(){...}
}

computed:{
    fullName:{
        get(){...},
        set(){...}
    }
}

由上可知,计算属性可以是一个函数,也可以是一个由getter和setter组成的对象

computed 也可以和 methods 方法混合起来用;

get( ) 代表:你什么值都不传进来,那我就给你返回一个默认的值;

set( ) 代表:你传一个值进来, 那就把名字设置为你传的这个值;

通过这样的 getter 和 setter ,就可以让计算属性实现更改,点击按钮改名字时,计算属性的值会发生变化,重新计算,页面会对应的刷新。但是如果再点,页面就不会再刷新了,不会再屏幕空白一下再显示出来:这是因为计算属性的结果会被缓存,只有在它的相关依赖发生改变时才会重新计算,所以再点改名字,页面是不会刷新的;

Watch

Watch 是监听、观察的意思,作用是:当数据变化时,执行一个函数;

Watch属性可以是字符串、函数、对象、数组

拥有deep、immediate两个属性

实例一:

new Vue({
    data:{
        n:0,
        obj:{
            a:'hello'
        }
    },
    template:`
		<div>
			<p>{{n}}</p>
			<button @click="n += 1">n+1</button>

			<p>{{obj.a}}</p>
			<button @click="obj.a += 'World'">obj.a + 'World'</button>

			<p>{{obj}}</p>
			<button @click="obj = {b:'b'}">obj = 新对象</button>
		</div>
	`,
    watch:{
        n(){
            console.log('n变了')
        },
        "obj.a"(){
            console.log('obj.a变了')
        },
        obj(){
            console.log('obj变了')
        }
    }
}).$mount('#app')

点击 n+1 按钮,打印 n变了

点击 obj.a + 'World' 按钮,打印出 obj.a 变了,但是没有打印 obj变了

点击 obj = 新对象 按钮,打印出 obj变了, 但是没有打印 obj.a 变了

由上可知:watch 的监听方式是:简单数据看值,复杂数据看地址;

那如果我想实现,我监听obj这儿对象,它里面的 obj.a 变了后,我也能知道,可以吗?

可以,这就要用到 deep 了:

deep

watch:{
   n(){
       console.log('n变了')
   },
   "obj.a"(){
       console.log('obj.a变了')
   },
   obj(){
       console.log('obj变了')
       deep:true
   }
}

加上 deep 选项后,我们再点击 obj.a + 'World' 按钮时,打印出 obj.a 变了,然后点 obj = 新对象 按钮时,会打印出:obj.a 变了,obj变了

所以 deep:true 会监听到对象的所有内部属性,默认值为 false

immediate

new Vue({
    data:{
        firstName:'Jack',
        lastName:'Lee',
        fullName:''
    },
    watch:{
        firstName:{
            handler:'change'
        }
    },
    /* 监听 firstName 属性,当 firstName 发生变化时,调用 change 函数,这个函数写在 methods里 */
    template:`
		<div>
			{{fullName}}
			<button @click=" firstName = 'Tom' ">改名字</button>
		</div>
	`,
    methods:{
        change(){
            this.fullName = this.firstName + ' ' + this.lastName
        }
    }
}).$mount('#app')

运行代码后,页面上什么也没有,只有一个改名字按钮:

明明不是在 template 里写了 {{ fullName }}了吗?为什么屏幕上什么都没有?至少该有个 data 里的默认值:Jack Lee 吧?

这是因为 watch 不会监听第一次变化!

我们点击按钮后,出现了 @click 里写的值:

那我想第一次就有值行不行?不能让页面空着吧?

行,用 immdiate选项 :

wacth:{
    firstName:{
        handler:'change',
        immediate:true
    }
}

初始页面就变成了我们原先设想的那样:

也就是,当 immediate:true 时,回调函数会在监听开始后立即执行;

总结

computed是计算属性,watch是监听、观察;

computed是用来计算一个值的,这个值我们在调用的时候不用加括号,直接当属性用就行;

computed根据依赖会自动缓存,如果依赖没变,computed就不会重新计算;

wacth是当监听的数据变化时,执行一个函数;

wacth里有两个选项,deep 和 immediate:deep 为真时就代表如果监听一个对象,还会监听对象里的属性变化,immediate表示在第一次渲染时,是否执行这个函数;