Vue computed 和 watch 浅析

282 阅读3分钟

Computed(计算属性)

当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值。

计算函数,复杂的计算都应该放在这里,尽量不要直接在模板语法里面计算,在此处计算的值是会动态变的,即计算的数中有一个值变了,最终结果也会跟着变

我们直接来例子:

// 引用完整版 Vue
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
  data() {
    return {
      num1: 10,
      num2: 20,
      nums: 5
    };
  },
  computed: {
    addNum: {
      get() {
        return Number(this.nums) + Number(this.num1) + Number(this.num2);
      },
      set(value) {
        console.log(value);
      }
    }
  },
  template: `
    <div>
     // 这里就是计算出来的addNum
      {{addNum}}
      </div>
    </div>
  `,
  methods: {}
}).$mount("#app");

上面代码就用到了computed。如果有很大的计算量的代码。就可以放在computed里面这样不会让你的代码看着很凌乱,让你的代码的逻辑看着更加的清晰,还有如果修改了里面的值,他会自动发更新结果。

看的不是很明白?

// 引用完整版 Vue
import { has } from "core-js/core/dict";
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
  id += 1;
  return { id, name, gender };
};
new Vue({
  data() {
    return {
      users: [
        createUser("方方", "男"),
        createUser("圆圆", "女"),
        createUser("小新", "男"),
        createUser("小葵", "女")
      ],
      gender:""
    };
  },
  computed:{
    displayUsers(){
      const hash = {
        male:'男',
        female: '女'
      }
      const  {users ,gender}= this;
      if (gender === '') {
        return this.users
      }else if (typeof gender === string){
        return this.users.filter(u=>u.gender === hash[gender]);
      }
  }
  },
  methods:{
    setGender(string){
      this.gender = string
    }
  },
  // 如何给三个按钮加事件处理函数
  // 使用 computed
  template: `
    <div>
      <div>
      <button @click="setGender('')">全部</button>
      <button @click="setGender('male')">男</button>
      <button @click="setGender('female')">女</button></div>
      <ul>
        <li v-for="u in displayUsers" :key="u.id">
          {{u.name}} - {{u.gender}}
        </li>
      </ul>
    </div>
  `
}).$mount("#app");

这里的computed就是一个稍微大一点的计算量了。可以看到,我们在里面有个对于性别的判断。获取性别后就会去过滤,是的在点击按钮时出现相同性别的信息。

注意

computed是有缓存的,也就是,如果依赖的属性没有变化,技术属性就不会在算一次。

我们看上面的例子。如我们点击全部,男,女。都会进行计算,但是如果我们连续的点击单独的一个按钮,他不会每次都计算,只会计算一次。

getter I setter默认不会做缓存,Vue 做了特殊处理。

Watch(侦听)

官方文档

用途:用户在数据变化的时候,执行一个函数。

// 引用完整版 Vue
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
  data: {
    n: 0,
    history: [],
    inUndoMode: false
  },
  watch: {
    n: function(newValue, oldValue) {
      console.log(this.inUndoMode);
      if (!this.inUndoMode) {
        this.history.push({ from: oldValue, to: newValue });
      }
    }
  },
  // 不如用 computed 来计算 displayName
  template: `
    <div>
      {{n}}
      <hr />
      <button @click="add1">+1</button>
      <button @click="add2">+2</button>
      <button @click="minus1">-1</button>
      <button @click="minus2">-2</button>
      <hr/>
      <button @click="undo">撤销</button>
      <hr/>

      {{history}}
    </div>
  `,
  methods: {
    add1() {
      this.n += 1;
    },
    add2() {
      this.n += 2;
    },
    minus1() {
      this.n -= 1;
    },
    minus2() {
      this.n -= 2;
    },
    undo() {
      const last = this.history.pop();
      this.inUndoMode = true;
      console.log("ha" + this.inUndoMode);
      const old = last.from;
      this.n = old; // watch n 的函数会异步调用
      this.$nextTick(() => {
        this.inUndoMode = false;
      });
    }
  }
}).$mount("#app");

整个代码就实现了,当我们对一个数进行加减时,watch会侦听这个动作,然后记录下来。

image-20210317201308482

同时watch还能模拟computed代码示例

什么是变化

我们直接看代码

// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

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");

这个代码实现的功能是:当我们点击按钮可以观察谁真正的变动了,例如我们点击了第一个按钮就会出现如下:

image-20210317202627094

显示 n 变了。

这里得出结论:

  • 如果把简单的数据类型变了 也就是上面的 n += 1那么他就是变化了。
  • 如果把对象里面的一个属性的值变了。也就是 obj.a += 'hi。对象里面的值变了,但是对象是没有变的,原因就是对象存的是一个固定的地址。
  • 如果地址改了那么对象才会变化。

如果我们想要对象里面的值obj.a变动了告诉对象obj你也变化了.

就可以用 deep:true

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

那么我们得出:

如果obj.a变了,请问obj算不算也变了

  • 如果你需要答案是「也变了」

    那么就用deep : true

  • 如果你需要答案是「没有变」

    那么就用deep:false

  • deep的意思是,监听object的时候是否往深了看

watch后面不能用箭头函数,this会指向全局对象

computed 和 watch 的区别

computed就是计算属性。

computed就是计算一个属性的,调用他的时候不需要加括号。

二是,他会根据依赖自动缓存功能,如果依赖不变,他就不会去重新计算。

watch就是监听、侦听。

如果一个属性变化了我们就去执行一个函数。

支持异步的

watch有2个选项。

  • 1个是 immediate:表示 是否在第一次渲染的时候执行函数。
  • 2个是 deep:如果我们监听一个对象,是否要看对象里面的变化。

资料来源:饥人谷

本文为贰贰的原创文章,著作权归本人和饥人谷所有,转载务必注明来源