Vue 中 computed 与 watch 的区别

302 阅读1分钟

字面上的区别

  • computed计算属性,它会根据你所依赖的数据动态显示新的计算结果
  • watch 是一个对 data 的数据监听回调, 当依赖的 data 的数据变化时, 会执行一个回调函数。在回调中会传入 newValoldVal 两个参数。

各自的作用

computed

new Vue({
  el: '#app',
  data: {
    message: 'hello'
  },
  template: `
      <div>
          <p>原始字符串: "{{ message }}"</p>
          <p>反转字符串: "{{ computedMessage}}"</p> 
      </div>
  `,
  computed: {
    // 计算属性的 getter
    computedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

// 原始字符串: "hello"
// 反转字符串: "olleh"

computedMessage 的值由 message.split('').reverse().join('') 计算得到,computedMessage 使用时不需要加括号,可以直接作为属性使用,展示在页面中

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 { users, gender } = this;
            if (gender === "") {
                return users;
            } else if (typeof gender === "string") {
                return users.filter(u => u.gender === hash[gender]);
            } else {
                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.gender}}
            </li>
        </ul>
    </div>
    `
}).$mount("#app");

点击不同的按钮时,计算结果发生变化,重新计算后页面更新。

计算属性的结果会被缓存,并且计算属性只有在它的相关依赖发生改变时才会重新计算。所以再次点击相同按钮时,由于计算结果不变,就不会重新计算。

watch

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

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

  • 拥有 deepimmediate 属性

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 变了"
  • 注意obj.a 变化时, obj 并没有发生改变;obj 变化时, obj.a 也没有发生改变

  • 推测watch 的监听方式是——简单数据类型看值,复杂数据类型(对象)看地址

deep
  • 那如果想通过监听 obj ,也能发现obj.a 的变化,可以实现吗?
// 使用 deep 可以实现
watch: {
    n() {
        console.log("n 变了");
    },
    obj: {
        handler(){
            console.log("obj 变了");
        },
        deep: true
    },
    "obj.a": function() {
        console.log("obj.a 变了");
    }
    }
}).$mount("#app");
  
  // 点击 "obj=新对象" , 得 "obj 变了"、"obj.a 变了"
immediate

在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调

总结

  1. 如果一个数据依赖于其他数据,那么把这个数据设计为 computed 的  

  2. 如果需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化

watch 可以执行异步而 computed 不行

本文参考摘录了:

  1. Vue 里的 computed 和 watch 的区别---白日梦
  2. 《简述Vue 里面 computed 和 watch 的区别》---用户7118714082313
  3. 面试题: Vue中的 computed 和 watch的区别---飞旋的留恋
  4. $watch
  5. Vue 的 computed 和 watch 的区别---Jacky