Vue 中 computed 与 watch的区别

112 阅读2分钟

computed

computed是计算属性的

它会根据所依赖的数据动态显示新的计算结果,计算的结果会被缓存起来

computed的值在getter执行后是会被缓存的。如果所依赖的数据发生改变时候,就会重新调用getter来计算最新的结果。

根据 Vue 文档例子来理解computed的使用

computed设计的初衷是为了使模板中的逻辑运算更简单

<body>
  <div id="app">
    {{ msg.split('').reverse().join('') }}
  </div>
  <script type="text/javascript">
    new Vue({
      el: '#app',
      data: {
        msg: 'hello'
      }
    });
  </script>
</body>

我们在vue模板中会对该数据值进行反转操作后输出数据, 因此在页面上就会显示 olleh

如果页面中的运算比这个还更复杂的话, 这个时候我们可以使用computed来进行计算属性值。把上面的代码改写成下面如下代码:

<body>
  <div id="app">
    <p>原来的数据: {{ msg }}</p>
    <p>反转后的数据为: {{ reversedMsg }}</p>
  </div>
  <script type="text/javascript">
    var vm = new Vue({
      el: '#app',
      data: {
        msg: 'hello'
      },
      computed: {
        reversedMsg() {
          // this 指向 vm 实例
          return this.msg.split('').reverse().join('')
        }
      }
    });
  </script>
</body>

如上代码, 我们在computed中声明了一个计算属性reversedMsg。我们提供的reversedMsg函数, 将用作属性 vm.reversedMsggetter函数

我们也可以打开控制台, 当我们修改 vm.msg 的值后, vm.reversedMsg 的值也会发生改变,如下控制台打印的信息可知:

vm.msg = '111'

'111'

vm.reversedMsg

'111'

我们的vm.reversedMsg的值依赖于vm.msg的值,当vm.msg的值发生改变时, vm.reversedMsg的值也会得到更新

computed应用场景

  1. 适用于一些重复使用数据或复杂及费时的运算。我们可以把它放入computed中进行计算, 然后会在computed中缓存起来, 下次就可以直接获取了。

  2. 如果我们需要的数据依赖于其他的数据的话, 我们可以把该数据设计为computed中。


watch的用法

watch用于侦听data的数据。

data数据发生变化,执行函数。在函数中会传入newValoldVal两个参数

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

拥有deep,immediate两属性

示例

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>
    </div>
  `,
  watch: {
    n() {
      console.log("n 变了");
    },
    obj() {
      console.log("obj 变了");
    },
    "obj.a": function() {
      console.log("obj.a 变了");
    }
  }
}).$mount("#app");

点击n+1 : 打印出“n 变了”

点击obj.a + 'hi' : 打印出“obj.a 变了”,不打印"obj 变了"

不点击obj.a + 'hi' , 点击obj = 新对象: 打印出"obj 变了",不打印"obj 变了"

说明watch的监听方式是:简单数据类型看值,复杂数据类型(对象)看地址 ,但可以通过deep监听obj内部obj.a的变化

使用deep属性

watch: {
    n() {
      console.log("n 变了")
    },
    obj() {
      console.log("obj 变了")
      deep: ture       // 可以监听到obj对象的所有内部属性
    },
    "obj.a": function() {
      console.log("obj.a 变了")
    }
  }

点击obj.a + 'hi' : 打印出“obj.a 变了” "obj 变了"

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

immediate属性

new Vue({
  data: {
    firstName: 'Jacky',
    lastName: 'Lee',
    fullName: ''
  },
  watch: {
    firstName: {
      handler: 'change'
    }
  },
  template: `
    <div>
      {{fullName}}
      <button @click="firstName='John'">改名字</button>
    </div>
  `,
  methods: {
    change() {
      this.fullName =  this.firstName + ' ' + this.lastName      
    }
  }
}).$mount("#app");

运行上面代码,页面啥也没有,然后点击“改名字”,页面依然显示 John Lee,并未发生变化

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

改造一下

watch: {
    firstName: {
      handler: 'change',
      immediate: ture
    }
}

immediate:true 时,回调函数会在监听开始后立刻执行,可以监听到到第一次变化。

总结:

computed是用来计算一个值的,使用时不需要加括号,可以直接当属性使用。computed拥有依赖缓存特性,如果依赖值不变,computed不会重新计算

watch是用来监听的,有两个选项,immediatedeep,当 immediate: true 时,表示会在第一次运行是执行这个函数,当 deep:true 时,如果监听一个对象,会同时监听其内部属性。watch没有依赖缓存特性。