computed
不使用 computed
通过简单的字符串拼接
import Vue from 'vue'
new Vue({
el: '#root',
template: `
<div>
<span>Name: {{firstName + ' ' + lastName}}</span>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou'
}
})
使用 computed
new Vue({
el: '#root',
template: `
<div>
<span>Name: {{name}}</span>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou'
},
computed: {
name () {
return `${this.firstName} ${this.lastName}`
}
}
})
使用 methods
显示结果和使用 computed 相同
new Vue({
el: '#root',
template: `
<div>
<span>Name: {{name}}</span>
<span>Name: {{getName()}}</span>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou'
},
computed: {
name () {
return `${this.firstName} ${this.lastName}`
}
},
methods: {
getName () {
return `${this.firstName} ${this.lastName}`
}
}
})
使用 computed 的好处
当我们改变 number 时,整个应用会重新渲染,vue 会被数据重新渲染到 dom 中。这时,如果我们使用 getName 方法,随着渲染,方法也会被调用,而 computed 不会重新进行计算,从而性能开销比较小。当新的值需要大量计算才能得到,缓存的意义就非常大。
如果 computed 所依赖的数据发生改变时,计算属性才会重新计算,并进行缓存;当改变其他数据时,computed 属性 并不会重新计算,从而提升性能。
当我们拿到的值需要进行一定处理使用时,就可以使用 computed。
import Vue from 'vue'
new Vue({
el: '#root',
template: `
<div>
<p>Name: {{name}}</p>
<p>Name: {{getName()}}</p>
<p>Number: {{number}}</p>
<p><input type="text" v-model="number"/></p>
<p>FirsName: <input type="text" v-model="firstName"/></p>
<p>LaseName: <input type="text" v-model="lastName"/></p>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou',
number: 0
},
computed: {
name () {
console.log('new name')
return `${this.firstName} ${this.lastName}`
}
},
methods: {
getName () {
console.log('getName invoked')
return `${this.firstName} ${this.lastName}`
}
}
})
computed 设置的操作
通过 computed 的 set 方法,可以进行设置的操作。
如下例,通过改变 name 的值,也可以改变 computed 属性 name 所以来的 firstName 和 lastName 的值。
不推荐这样做,一般 computed 属性数据是根据多重数据组合成的新的数据,组合容易,但拆开重新设置并不容易
template: `
<div>
<p>Name: <input type="text" v-model="name"/></p>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou',
},
computed: {
name: {
get () {
console.log('new name')
return `${this.firstName} ${this.lastName}`
},
set (name) {
const names = name.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
},
watch
例如,监听 firstName 数据,并根据改变得到的新值,进行某些操作。
new Vue({
template: `
<div>
<p>FullName: {{fullName}}</p>
<p>FirsName: <input type="text" v-model="firstName"/></p>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou',
fullName: ' '
},
watch: {
firstName (newName, oldName) {
this.fullName = newName + ' ' + this.lastName
}
}
})
注意:上例中,初始 fullName 是没有值的,只有当数据改变时,才会显示。因为 watch 的方法默认是不会执行的,只有当监听数据变化,才会执行。
immerdiate 属性
通过声明 immediate 选项为 true,可以立即执行一次 handler。
watch: {
firstName: {
handler (newName, oldName) {
this.fullName = newName + ' ' + this.lastName
},
immediate: true
}
},
watch 并不适用于显示某一个数据以及数据的拼装等。watch 用在监听数据变化,做某些指令操作(给后台发数据请求)
deep属性
不使用 deep 时,当我们改变 obj.a 的值时,watch不能监听到数据变化,默认情况下,handler 只监听属性引用的变化,也就是只监听了一层,但改对象内部的属性是监听不到的。
new Vue({
template: `
<div>
<p>Obj.a: <input type="text" v-model="obj.a"/></p>
</div>
`,
data: {
obj: {
a: '123'
}
},
watch: {
obj: {
handler () {
console.log('obj.a changed')
},
immediate: true
// deep: true
}
}
})
通过使用 deep: true 进行深入观察,这时,我们监听 obj,会把 obj 下面的属性层层遍历,都加上监听事件,这样做,性能开销也会变大,只要修改 obj 中任意属性值,都会触发 handler。
如何优化?
在字符串中,写 obj 深入的属性调用,vue 会层层解析,找到 a,并进行监听。
watch: {
'obj.a': {
handler () {
console.log('obj.a changed')
},
immediate: true
// deep: true
}
}
注意
不要在 computed 或 watch 中,去修改所依赖的数据的值,尤其是 computed;如果这样做,可能导致一个无线循环的触发。