Vue构造选项之computed与watch

360 阅读2分钟

1 computed

1.1 特点

  • 计算属性,看上去是方法,但实际上是实例计算属性
  • 这个属性不需要调用直接可以在 DOM 里使用
<template>
  <div class="app">
      {{functionName}} //直接渲染到页面
  </div>
</template>
<script>
    .....
    computed: {
       functionName() {return ...}
    }
</script>
  • 会根据你所依赖的数据动态显示新的计算结果
  • 计算属性如果依赖不变的话,它就会变成缓存,computed的值就不会重新计算
  • 所有getter和setter的this自动地绑定为Vue实例
  • 简化了template模板内{{}}中的内容,这也是computed的设计初衷

1.2 语法

computed:{
 [key: string]: Function | { get: Function, set: Function } 
 }
  • 实例1,此处Function默认为getter
<script>
    .....
    computed: {
        functionName() {return ...}//返回值渲染到页面 
    }
</script>
  • 实例2,此处Function分别为getter和setter
<script>
   data:{
       n:0
   }
    computed: {
        functionName:{
            get() { 
            return this.n
            }
            set(value) {
            this.n=value 
            }
        },
    }
</script>
<template>
   <button @click='functionName=1'></button> //设置functionName,n设置为1
   <div> {{functionName}}</div> //读取functionName,1渲染到页面
</template>

2 watch

2.1 特点

  • 监听/侦听,当数据变化时,执行一个函数
  • Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性
  • 当监听的数据变化时,Vue会自动传入 newVal 和 oldVal
<script>
  new Vue({
    data: {
      n: 0
  },
  watch: {
    n(newValue, oldValue) {
      console.log(newValue,oldValue)
      }
  },
</script>
<template>
    <div>
      {{n}}
      <button @click="n=1">n+1</button>
    </div>
</template>
//newValue:1
//oldValue:0
  • 如果你需要在某个数据变化时做一些事情,使用watch
  • 不应该使用箭头函数来定义 watcher 函数

2.2 注意事项

  • 用watch可以模拟computed的功能,但是并不建议这么做
new Vue({
  data: {
    user: {
      nickname: "方方",
      phone: "13812312312"
    },
    displayName: ""
  },
  watch: {
    "user.nickname": {
      handler: "changed",
      immediate: true 
    },
    "user.phone": {
      handler: "changed",
      immediate: true
  },
  template: `
    <div>
       {{displayName}}
       <button @click="user.nickname=undefined">remove nickname</button>
    </div>
  `,
  methods: {
    changed() {
      const user = this.user;
      this.displayName = user.nickname ||user.phone;
    }
  }
}).$mount("#app");

->点击button,方方消失,13812312312出现
->虽然也可实现computed的功能,但displayName是Vue实例的真正属性,而不是计算属性
->'immediate: true'表示第一次渲染是也触发 watch
->从上面例子看到,如果是多级属性,watch可以这样写:

watch: {
    "user.nickname": {
       function(){}
    }
  • watch是异步的
watch:{
    n(){
        console.log(this.mode)
    }
}
methods:{
 this.mode = true;
 this.n = old; // watch n 的函数会异步调用
 this.mode = false //上一句执行完会立刻执行这一行,mode会马上false
 }
 //

为了让watch n 函数输出为true,可以使用Vue提供的$nextTick():

this.inUndoMode = true
this.n = old
this.$nextTick(() => {  
    this.inUndoMode = false //可以简单理解为:等一会再执行这行代码
}

2.3 watch完整语法

语法1:

watch:{
    a: function (newVal, oldVal) {...},
    // 方法名
    b: 'someMethod',
    c: {
      handler: function (newVal, oldVal) {...},
    },
    d: {
      handler: 'someMethod',
      immediate: true
    },
    e: [
      'handle1',
      function handle2 (newVal, oldVal) {...},
      {
        handler: function handle3 (newVal, oldVal) {...},
      }
    ],
    'e.f': function (val, oldVal) {...}
}

语法2:

vm.$watch('xxx',fn,{deep:...,immediate:...})

3 对数据变化的理解

3.1 简单数据类型

简单数据类型看值,值变了则数据变化了

data: {
   n:0
}
//data.n=1,则n变化了

3.2 复杂数据类型(对象)

复杂类型(对象)看地址,地址变化了则数据变化了

data: {
   n:0
}
//data.n=1,n变化了,data没有变化
//data:{n:0},重新对data赋值,data变化了

3.3 'deep:true'选项

你可以利用Vue提供的'deep:true'选项来控制数据的变化

new Vue({
  data:{
    obj:{
        n:0
        m:0
    }
  },
  watch:{
      n(){},
      m(){},
      obj:{
          handler(){}
          deep:true
      }
  }
})
//添加'deep:true'选项后,如果n或m变化了,obj也随之变化了