前言
在上一篇文章中,讲过了vue的模板语法,今天我们要深入了解一下vue的data/methods/computed/watch的用法。之前的文章中有用过部分内容,通过今天的文章,你将对vue的这些方法有一个更深层次的理解。
data
定义数据的时候,是在vue创建实例的时候去写一个data函数,这个函数在之前的内容中也是经常用到的。在data函数中,会把对应的数据通过return返回给模板,在模板中就可以使用相应的数据。
在之前的内容中,我们知道可以在浏览器控制台通过vm.$data去改变data函数中的数据值,其实在vue里面可以去掉$data也可以改变data函数中的数据值。
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World' } }, template: "<div>{{message}}</div>" }); const vm = app.mount('#root'); </script> 复制代码
methods
在methods中,我们可以定义模板中使用到的各种方法,在之前的内容中,我们也用到过。
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World' } }, methods: { handleClick(){ this.message = 'bye' } }, template: "<div v-on:click='handleClick'>{{message}}</div>" }); const vm = app.mount('#root'); </script> 复制代码
在methods中定义的方法,是有一个this的,这个this就表示vue实例,通过this可以直接修改data方法中的数据值。
如果你想要获取到vue实例的this指向,就不能在methods中定义的方法上使用箭头函数。
methods: { handleClick: () => { console.log('通过箭头函数打印data函数中的值:', this.message) } }, 复制代码
在浏览器控制台中可以看到,打印出来的是undefined,其实这时候的this指向的并不是vue实例了,而是window,有兴趣的小伙伴可以直接打印this看看返回值。
methods中的函数除了通过v-on绑定的事件去触发,还可以直接在插值表达式中使用。
const app = Vue.createApp({ data(){ return { message: 'Hello World' } }, methods: { formatString: (string) => { return string.toUpperCase() } }, template: "<div>{{formatString(message)}}</div>" }); const vm = app.mount('#root'); 复制代码
在浏览器中刷新之后,可以直接渲染出大写字母HELLO WORLD。
computed
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World', count: 2, price: 4 } }, template: "<div>{{count * price}}</div>" }); const vm = app.mount('#root'); </script> 复制代码
通过上面这个代码可以看出,我们可以在插值表达式中直接去计算data函数中的数据值,但是直接在模板里面去计算,第一是如果计算量太大的话看起来不太美观,第二是没有很好的做到语义化。
理想状态下应该是可以在data函数中定义一个total,然后让total去计算count和price的值。但是data函数中不能直接在函数返回里面调用自身的数据,所以我们可以通过一个计算属性computed来完成这件事。
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World', count: 3, price: 5 } }, computed:{ total(){ return this.count * this.price } }, template: "<div>{{total}}</div>" }); const vm = app.mount('#root'); </script> 复制代码
- 在
computed中定义一个total函数,在函数中返回计算好的数值,就可以在插值表达式中直接使用total,并不需要像methods中的函数一样,去给插值表达式中的total添加一个()代表函数。
- 通过修改
data函数中的数据值,computed中的函数会重新进行计算然后将新的数据值返回到模板中渲染出来。
computed和methods对比
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World', count: 4, price: 7 } }, methods: { getTotal(){ return this.count * this.price } }, template: "<div>{{getTotal()}}</div>" }); const vm = app.mount('#root'); </script> 复制代码
可能有些人会有疑问,这个计算方式完全可以通过methods中的方法去完成,为什么要使用computed呢?
- 通过下面的例子,你会发现
computed和methods的区别了。
const app = Vue.createApp({ data(){ return { message: 'Hello World', count: 4, price: 7 } }, computed:{ time(){ return Date.now() } }, methods: { getTime(){ return Date.now() } }, template: `<div> <div>computed - {{message}} - {{time}}</div> <div>methods - {{message}} - {{getTime()}}</div> </div>` }); const vm = app.mount('#root'); 复制代码
我们在computed和methods中都返回当前时间戳,然后我们去浏览器控制台修改message的值,看看这两个之间的具体区别。
通过浏览器输出的内容可以看出,当message值改变之后,computed返回的时间戳是不变的,而methods中的方法返回的时间戳是随着页面数据改变而改变的。
因为当页面重新渲染之后,methods中的方法也会随之重新渲染,而computed中只有依赖的数据发生变化时,才会重新执行计算。
watch
<script> const app = Vue.createApp({ data(){ return { message: 'Hello World', count: 4, price: 7 } }, watch: { price(){ setTimeout(() => { console.log('price change') }, 3000) } }, template: `<div>{{message}}</div>` }); const vm = app.mount('#root'); </script> 复制代码
在watch中可以通过监听data函数中定义的数据,当数据发生变化时,可以执行一些异步操作。
- 在
watch中定义的监听方法中,有两个参数:当前值,上一个值
watch: { price(current, prev){ console.log(current, prev) } }, 复制代码
在watch中也可以执行computed计算属性那样的操作,但是由于watch的特殊性,需要现在data中去定义值,然后才能在watch中进行侦听,最后在返回到页面上进行渲染,所有根据代码的简约性来看,不建议使用watch去做computed中能做的事。
总结
computed和methods都能实现的功能,建议使用computed,因为会有缓存。computed和watch都能实现的功能,建议使用computed,因为更加简洁。
![]UWOD(KIB9LJS9~S[T{QHM9.png ]UWOD(KIB9LJS9~S[T{QHM9.png](https://ucc.alicdn.com/pic/developer-ecology/22e8b027e72c4965b150c8b3ca581207.png?x-oss-process=image/resize,w_1400/format,webp)


![5Z22HGI34E8)K[8]YZ4N4[2.png 5Z22HGI34E8)K[8]YZ4N4[2.png](https://ucc.alicdn.com/pic/developer-ecology/db71d07814ef4805ab665ca7bc78b6d2.png?x-oss-process=image/resize,w_1400/format,webp)

![TIA7J{L6QKA1XVR9]U4IR74.png TIA7J{L6QKA1XVR9]U4IR74.png](https://ucc.alicdn.com/pic/developer-ecology/8de2e60e3f4c4ea2947648c9c8cb2314.png?x-oss-process=image/resize,w_1400/format,webp)

![0BG2UM~[UM]S%(CY~_I}C@T.png 0BG2UM~[UM]S%(CY~_I}C@T.png](https://ucc.alicdn.com/pic/developer-ecology/ed9a8105a79047fabde26a15f57f3a06.png?x-oss-process=image/resize,w_1400/format,webp)
![$`UF]4Z6~%$~@XPVWW$8_LR.png $`UF]4Z6~%$~@XPVWW$8_LR.png](https://ucc.alicdn.com/pic/developer-ecology/114d19580b2a495982f1ab19a10e2e74.png?x-oss-process=image/resize,w_1400/format,webp)

![4_S)UPO5]HUPZ_T_RYR2HP7.png 4_S)UPO5]HUPZ_T_RYR2HP7.png](https://ucc.alicdn.com/pic/developer-ecology/2b7611cf3e0f409fab277faa63e73a83.png?x-oss-process=image/resize,w_1400/format,webp)