土豆博客

vue中的watch和computed详解

# 一、computed

computed擅长处理的场景:一个数据受多个数据的影响

那么问题来了:什么是一个数据受多个数据影响

看下面的例子:

<body>
    <div id="app">
        {{price}}
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        const app = new Vue({
            el:"#app",
            data:{
                count:10,
                money:100
            },
            computed: {
                price() {
                    return this.money*this.count //结果为1000
                }
            },
        })
    </script>
</body>

这个例子中我需要计算最终的价钱price并显示到页面中,这个price就相当于我需要计算的这一个数据,而这个price受到countmoney的影响,也就是说,countmoney的值会影响price最终的值,这就是所谓的一个数据受多个数据影响

我们再来看看这个例子:

<body>
    <div id="app">
        {{getPrice()}}
        <button @click="getPrice">计算</button>  <!-- 调用getPrice方法 -->
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        const app = new Vue({
            el:"#app",
            data:{
                count:10,
                money:100
            },
            
            methods: {
                getPrice() {
                    console.log("我被重新计算了")  //注意这行
                    return this.count*this.money
                }
            },
        })
    </script>
</body>

我们将上面的例子用method方法重新改写,也实现了计算price的值,当多次点击按钮的时候,控制台则会显示

QQ图片20200212094940.png

也就是说, 即使getPrice中的计算所依赖的值并没有发生改变,每次调用getPrice方法也会重新打印一次,换句话说,method方法并不支持缓存

接着用computed方法再进行改造一次

<body>
    <div id="app">
        {{getPrice}}
        <button @click="count=10">计算</button>   
        <!-- 在这里触发点击方法使count赋值(但值不改变,仍为原来的值10)响应computed -->
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                count: 10,
                money: 100
            },

            computed: {
                getPrice() {
                    console.log("我被重新计算了")
                    return this.count * this.money
                }
            },
        })
    </script>
</body>

当多次点击按钮的时候,控制台则会只显示一次我被重新计算了,也就是说,computed支持缓存,只有依赖数据发生改变,才会重新进行计算 ,不支持异步,当computed内有异步操作时无效,无法监听数据的变化,

如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

# 二、watch

watch擅长处理的场景:一个数据影响多个数据

那么问题又来了:什么是一个数据影响多个数据

举个栗子,我们需要实现一个功能,当路由跳转变化的时候,打印上一个路由,和当前的路由

<body>
    <div id="app">
        <router-link to="/first">first</router-link>
        <router-link to="/second">second</router-link>
        <router-view></router-view>
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <script>
        const First = {  //创建组件First
            template: `
            <div>first</div>
            `
        }
        const Second = { //创建组件Second
            template: `
            <div>second</div>
            `
        }
        const routes = [  //创建路由规则
            { path: '/first', component: First },
            { path: '/second', component: Second }
        ]
        const router = new VueRouter({  //创建VueRouter实例,并把规则挂载到路由
            routes
        })
        const app = new Vue({
            el: "#app",
            watch: {
                "$route.path":function(newVal,oldVal) { 
                    //在这里newVal代表当前的路由,oldVal代表跳转之前的路由
                    console.log(newVal,oldVal)
                }
            },
            router  //将路由实例挂载都Vue实例上
        })
    </script>
</body>

可以看到,当我们由first路由跳到second路由的时候,控制台就会打印

QQ图片20200212105824.png

在这里,你可以理解为一个数据:$route对象,影响多个数据:路由跳转之前的值,跳转之后的值

其次,watch不支持缓存,数据变,直接会触发相应的操作,但它支持异步,监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值,监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数

  • immediate:组件加载立即触发回调函数执行

  • deep: 深度监听

假设有以下代码

<body>
    <div id="app">
        <p>FullName: {{fullName}}</p>
        <p>FirstName: <input type="text" v-model="firstName"></p>
    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                firstName: 'Dawei',
                lastName: 'Lou',
                fullName: ''
            },
            watch: {
                firstName(newName, oldName) {
                    this.fullName = newName + ' ' + this.lastName;
                }
            }
        })
    </script>
</body>

上面的代码的效果是,当我们输入firstName后,wacth监听每次修改变化的新值,然后计算输出fullName。即firstName的改变影响了fullName

这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。换句话说,当打开页面的时候,{{fullName}}不会有值,那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:

watch: {
  firstName: {
    handler(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    },
    // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
    immediate: true
  }
}
# 三、总结

1.computed擅长处理的场景:一个数据受多个数据影响,computed支持缓存,只有依赖数据发生改变,才会重新进行计算 ,不支持异步,当computed内有异步操作时无效,无法监听数据的变化, 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

2.watch擅长处理的场景:一个数据影响多个数据,不支持缓存,数据变,直接会触发相应的操作,但它支持异步,监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值,监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数

  • immediate:组件加载立即触发回调函数执行

  • deep: 深度监听

当需要在数据变化时执行异步或开销较大的操作时,使用watch是最有用的。这是和computed最大的区别

code
top

扫码添加,一起进步

wechat-code

为了保障最佳预览体验,博客已不支持IE浏览器的访问,邀请您使用以下现代高级浏览器。

谷歌浏览器(推荐) 火狐浏览器

注:如果你使用的是360,QQ等双核浏览器,请开启极速模式