computed
是vue
的计算属性
,是根据依赖关系
进行缓存
的计算,只有在它的相关依赖
发生改变
时才会进行更新
。
<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)
的,这使它更易于测试和理解。
在vue组件
中使用reversedMessage
属性,vue
会自动调用computed
下的reversedMessage方法
。
computed
的每一个计算属性都会被缓存
起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新。下面代码中,计算属性total
,它依赖了a
和b
这两个属性,只要它们其中一个属性变化,total
就会重新执行。computed
计算属性会被缓存,在下面代码中使用了两次total
,但在控制台只输出了一次 compouted total
。<template>
<div>
<p>BTp>
<a @click="addA()">addAa> | <a @click="addB()">addBa>
<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>
在 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)
}
}
}
computed
写的属性不要在 data
重复写,跟 data
中的数据一样可以通过 vm.
获取或者修改get
函数setter
和 getter
响应的数据)发生改变了就会重新计算自己的值computed
的每一个计算属性都会被缓存
起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新。get
可以没有set
set
中不要给计算属性重新赋值,否则会产生死循环
第一次
获取的时候依赖值没有发生改变但是也会默认执行一次
在vue
中watch
用来监听数据的变化
,一旦发生变化可以执行一些其他操作。
<template>
<div>
<p>BTp>
<a @click="addA()">addAa> | <a @click="addB()">addBa>
<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>
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()">ATp>
<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>BTp>
<a @click="nameChange()">nameChangea> |
<a @click="ageChange()">ageChangea>
<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>
watch
可以监听对象
,也可以监听对象中的某个属性
。注意在监听对象时,可以通过配置deep
参数来决定是否要深度监听
。
<template>
<div>
<p>BTp>
<a @click="nameChange()">nameChangea> |
<a @click="ageChange()">ageChangea>
<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>
watch
中不要使用箭头函数,即不要用箭头函数来定义watcher
函数。因为箭头函数中的this
是指向当前作用域,对于箭头函数来说,箭头函数中的this
指向的是定义时的对象
而不是函数运行时
所在的对象,即全局定义时的window
对象。
computed
的get
必须有返回值(return
),而watch
return
可有可无computed
支持缓存
,只有依赖的数据发生改变,才会重新进行计算,而watch
不支持缓存,数据发生改变,会直接触发相应的操作computed
可以自定义名称
,而watch
只能监听
props
和data
里面名称相同的属性computed
适用于复杂的运算,而watch
适合一些消耗性功能,比如Ajax
computed
不支持异步
,当computed
内有异步操作是无效,无法监听数据的变化,而watch
支持异步
computed
属性值会默认走缓存
,计算属性是基于它们的响应式依赖进行缓存
的,也就是基于data
中声明过或者父组件传递的props中
的数据通过计算得到的值,而watch
监听的函数接受两个参数,第一个是最新的值
,第二个是输入之前的值
依赖其他属性
,多对一
或者一对一
,一般用computed
;当一个属性发生变化时,需要执行对应的操作,一对多
,一般用watch