一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 4 天,点击查看活动详情。
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
可以优先考虑使用计算属性,再或者侦听器。
计算属性 -- computed
- 计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
- 计算属性的依赖如果是非响应式的话,计算属性不会更新。
- 默认只有getter,不过在需要时也可以提供一个 setter
1. 在模板内使用表达式
<div id='app'>
<!--添加课程-->
<input type="text" v-model="course" v-on:keydown.enter="addCourse">
<button @click="addCourse">添加课程</button>
<!--课程展示-->
<ul>
<li v-for="item in courses" :key="item">
{{item}}
</li>
</ul>
<p>
<!-- 表达式 -->
课程数量: {{courses.length + '门'}}
</p>
</div>
const app = new Vue({
el: '#app',
data() {
return {
courses: ['JavaScript', 'vue', 'react', 'webpack', 'node', '小程序'],
course: ''
}
},
methods: {
addCourse() {
if(this.course) {
this.courses.push(this.course)
}
this.course = ''
}
}
})
2. 改用计算属性
计算属性的使用与普通响应式属性一样
<!--略-->
<p>
<!-- 计算属性 -->
课程数量:{{courseCount}}
</p>
<!--略-->
const app = new Vue({
// ......略
computed: {
courseCount() {
return this.courses.length + '门';
}
}
// ......略
})
3. 计算属性依赖如果是非响应式的
const app = new Vue({
el: '#app',
data() {
return {
courses: ['JavaScript', 'vue', 'react', 'webpack', 'node', '小程序'],
course: '',
dataReact: {} // 设置依赖属性
}
},
created() {
console.log('created')
// 计算属性的依赖如果是非响应式属性的话,计算属性不会更新
// this.dataReact.count = this.courses.length // 不更新
this.$set(this.dataReact, 'count', this.courses.length ) // 更新了
},
computed: {
courseCount() {
return this.dataReact.count + '门'
}
}
methods: {
addCourse() {
if(this.course) {
this.courses.push(this.course)
}
this.course = ''
this.dataReact.count = this.courses.length // 每次增加课程,这里得手动更新下
}
}
})
4. 什么时候需要使用setter
场景:例如页面显示一个时长。
一、取数据显示:这个时长从后端获取,后端返回的数据是秒(s), 页面需要显示的是分钟(min);
二、时长更新后,回传给后端——秒(s)
<!-- computed setter使用场景 -->
<div>
<div>时长:{{showTime}} min</div>
<div>回传后端的数据:{{duration}} s</div>
</div>
const app = new Vue({
el: '#app',
data() {
return {
duration: 0
}
},
computed: {
showTime: {
get() {
return (this.duration / 60).toFixed(2)
},
set(newValue) {
this.duration = newValue * 60
}
}
},
created() {
this.duration = 120;
setInterval(() =>{
this.duration++
}, 1000)
}
})
5. 计算属性如果使用箭头函数
注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。
// 原
courseCount() {
console.log('computed: courseCount')
return this.dataReact.count + '门'
}
// 箭头函数:
courseCount: (vm) => {
console.log('computed: courseCount')
return vm.dataReact.count + '门'
}
侦听器 —— watch
当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
拿上面的例子,改用watch
实现
1. 一般写法
// 实例化完后不会立即执行,当监听的数据courses改变时执行
watch: {
courses(newData, oldData) {
console.log('newData',newData)
console.log('oldData',oldData)
this.watchCourseCount = newData.length + '门'
}
},
2. 配置项
// 监听dataReact(这是个对象), 当其属性count改变时,触发更新
dataReact: {
immediate: true, // 立即调用
deep: true, // 会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
handler(newData, oldData) { // 执行函数
console.log('watch')
this.watchCourseCount = newData.count + '门'
}
}
注:
- 监听数组的变更不需要配置deep
- 不应该使用箭头函数来定义 watcher 函数
computed VS watch
- computed适用于多个值影响一个值的情形,也就是我当前计算属性值依赖于其他一个或多个值,有缓存性,只有当其依赖的响应式数据变化是,它才会跟着变。
- watch 适用于一个值变化影响多个值得情形,适合执行异步操作或比较打的开销。