vuejs计算属性computed & 监听属性watch

一、计算属性computed

1.1 什么是计算属性

computedvue计算属性,是根据依赖关系进行缓存的计算,只有在它的相关依赖发生改变时才会进行更新

<template>
  <div id="example">
    <p>Original message: "{
   
   { message }}"</p>
    <p>Computed reversed message: "{
   
   { reversedMessage }}"</p>
  </div>
</template>

<script>
export default {
      
      
  name: "CT",
  data() {
      
      
    return {
      
      
      message: "Hello",
    };
  },
  computed: {
      
      
    // 计算属性的 getter
    reversedMessage: function () {
      
      
      // `this` 指向 vm 实例
      return this.message.split("").reverse().join("");
    },
  },
};
</script>

可以像绑定普通 property 一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。

1.2 computed默认使用的是getter属性

vue组件中使用reversedMessage属性,vue会自动调用computed下的reversedMessage方法

1.3 computed的响应式依赖(缓存)

  1. computed的每一个计算属性都会被缓存起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新。下面代码中,计算属性total,它依赖了ab这两个属性,只要它们其中一个属性变化,total就会重新执行。
  2. computed计算属性会被缓存,在下面代码中使用了两次total,但在控制台只输出了一次 compouted total
<template>
  <div>
    <p>BT</p>
    <a @click="addA()">addA</a> | <a @click="addB()">addB</a>
    <p>total: {
   
   { total }}</p>
    <p>total: {
   
   { total }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "BT",
  data() {
      
      
    return {
      
      
      a: 1,
      b: 2,
    };
  },
  computed: {
      
      
    total() {
      
      
      console.log("compouted total ");
      return this.a + this.b;
    },
  },
  mounted() {
      
      },
  methods: {
      
      
    addA() {
      
      
      this.a++;
    },
    addB() {
      
      
      this.b++;
    },
  },
};
</script>

1.4 计算属性的 getter 与 setter

Vue 中,computed 的属性可以被视为是data 一样,可以读取和设值,因此在 computed 中可以分成 getter(读取)setter(设值),一般情况下是没有 setter 的,computed 预设只有 getter ,也就是只能读取,不能改变设值
vue.js计算属性默认只有 getter,因为是默认值所以我们也常常省略不写,如下代码:

<div id="demo">{
   
   { fullName }}</div>

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

其实computed里的代码完整的写法应该是:

computed: {
    fullName: {
      get(){
         return this.firstName + ' ' + this.lastName
      }
    }
  }

计算属性settter

computed: {
    
    
    fullName: {
    
    
      get(){
    
    
         return this.firstName + ' ' + this.lastName
      },
      set(newVal){
    
    
      	console.log(newVal)
      }
    }
 }

1.5 计算属性小结

  • 计算属性在 computed 写的属性不要在 data 重复写,跟 data 中的数据一样可以通过 vm. 获取或者修改
  • 只要获取某个计算属性就会触发对应的 get 函数
  • 只要是依赖的值(必须有 settergetter 响应的数据)发生改变了就会重新计算自己的值
  • computed的每一个计算属性都会被缓存起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新。
  • 计算属性必须要有get可以没有set
  • set中不要给计算属性重新赋值,否则会产生死循环
  • 第一次获取的时候依赖值没有发生改变但是也会默认执行一次

二、watch

2.1 watch用来处理什么场景

vuewatch用来监听数据的变化,一旦发生变化可以执行一些其他操作。

<template>
  <div>
    <p>BT</p>
    <a @click="addA()">addA</a> | <a @click="addB()">addB</a>
    <p>a: {
   
   { a }}</p>
    <p>b: {
   
   { b }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "BT",
  data() {
      
      
    return {
      
      
      a: 1,
      b: 2,
    };
  },
  computed: {
      
      },
  watch: {
      
      
    a() {
      
      
      console.log('a watch');
    }
  },
  mounted() {
      
      },
  methods: {
      
      
    addA() {
      
      
      this.a++;
    },
    addB() {
      
      
      this.b++;
    },
  },
};
</script>

2.2 watch参数

  • watch就是当值第一次绑定的时候,是不会执行监听函数的,只有值发生改变才会执行。如果需要在第一次绑定的时候也执行函数,则需要用到immediate属性,比如当父组件向子组件 动态传值时,子组件props首次获取到父组件传来的No认知时,也需要执行函数
  • handler方法:immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化时才执行
  • deep,当需要监听一个对象的变化时,普通的watch方法无法监听对象内部属性的变化,只有data中的数据才能够坚挺到变化,此时需要deep属性进行深度监听,设置deep: true当对象的属性较多时,每个属性的变化都会执行handler
<template>
  <div>
    <p @click="click()">AT</p>
    <BT :age="age"></BT>
  </div>
</template>

<script>
import BT from "./BT.vue";

export default {
      
      
  name: "AT",
  components: {
      
       BT },
  data() {
      
      
    return {
      
      
      age: 10,
    };
  },
  methods: {
      
      
    click() {
      
      
      this.age = Math.floor(Math.random() * 20 + 18);
    },
  },
};
</script>
<template>
  <div>
    <p>BT</p>
    <a @click="nameChange()">nameChange</a> |
    <a @click="ageChange()">ageChange</a>
    <p>name: {
   
   { person.name }}</p>
    <p>age: {
   
   { person.age }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "BT",
  props: {
      
      
    age: {
      
      
      type: Number,
    },
  },
  data() {
      
      
    return {
      
      
      person: {
      
      
        name: "BT",
        age: 20,
      },
    };
  },
  computed: {
      
      },
  watch: {
      
      
    person: {
      
      
      handler(newVal, oldVal) {
      
      
        console.log("newVal: ", newVal, "oldVal: ", oldVal);
      },
      deep: true,
      immediate: true
    },
    age: {
      
      
      handler(newVal, oldVal) {
      
      
        console.log("newVal: ", newVal, "oldVal: ", oldVal);
      },
      immediate: true
    },
  },
  mounted() {
      
      },
  methods: {
      
      
    nameChange() {
      
      
      this.person.name = "BT" + new Date();
    },
    ageChange() {
      
      
      this.person.age = Math.floor(Math.random() * 20 + 18);
    },
  },
};
</script>

2.3 监听对象

watch可以监听对象,也可以监听对象中的某个属性。注意在监听对象时,可以通过配置deep参数来决定是否要深度监听

<template>
  <div>
    <p>BT</p>
    <a @click="nameChange()">nameChange</a> |
    <a @click="ageChange()">ageChange</a>
    <p>name: {
   
   { person.name }}</p>
    <p>age: {
   
   { person.age }}</p>
  </div>
</template>

<script>
export default {
      
      
  name: "BT",
  data() {
      
      
    return {
      
      
      person: {
      
      
        name: "BT",
        age: 20,
      },
    };
  },
  computed: {
      
      },
  watch: {
      
      
    person: {
      
      
      handler(newVal, oldVal) {
      
      
        console.log("newVal: ", newVal, "oldVal: ", oldVal);
      },
      deep: true
    },
    "person.age": {
      
      
      handler(newVal, oldVal) {
      
      
        console.log("newVal: ", newVal, "oldVal: ", oldVal);
      },
    },
  },
  mounted() {
      
      },
  methods: {
      
      
    nameChange() {
      
      
      this.person.name = "BT" + new Date();
    },
    ageChange() {
      
      
      this.person.age = Math.floor(Math.random() * 20 + 18);
    },
  },
};
</script>

2.4 不要使用箭头函数

watch中不要使用箭头函数,即不要用箭头函数来定义watcher函数。因为箭头函数中的this是指向当前作用域,对于箭头函数来说,箭头函数中的this指向的是定义时的对象而不是函数运行时所在的对象,即全局定义时的window对象。

三、watch 和 computed 的区别

  1. computedget必须有返回值(return),而watch return可有可无
  2. computed支持缓存,只有依赖的数据发生改变,才会重新进行计算,而watch不支持缓存,数据发生改变,会直接触发相应的操作
  3. computed可以自定义名称,而watch只能监听 propsdata里面名称相同的属性
  4. computed适用于复杂的运算,而watch适合一些消耗性功能,比如Ajax
  5. computed不支持异步,当computed内有异步操作是无效,无法监听数据的变化,而watch支持异步
  6. computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值,而watch监听的函数接受两个参数,第一个是最新的值,第二个是输入之前的值
  7. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性多对一或者一对一,一般用computed;当一个属性发生变化时,需要执行对应的操作,一对多,一般用watch

参考

猜你喜欢

转载自blog.csdn.net/letianxf/article/details/128529064