计算属性和侦听器
computed 计算属性
computed特性
- 监听依赖值变化,当被调用时,根据相关的计算逻辑,返回计算结果
- 具有缓存性,当依赖值变化才会执行计算,依赖值未变化则返回上一次计算结果从而提升性能
- 计算属性必须同步执行,不能执行异步任务
computed 使用
- 常规用法
<style lang='scss' scoped>
/* @import url(); 引入公共css类 */
.mk-card {
border-radius: 4px;
border: 1px solid #ebeef5;
background-color: #fff;
overflow: hidden;
color: #303133;
&.is-shadow {
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
&--primary {
.mk-card__header {
background: #409eff;
color: #fff;
}
}
&__header {
padding: 12px 24px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-content: center;
}
&__content {
padding: 20px;
}
}
.mk-list {
list-style: none;
text-align: left;
&__item {
display: flex;
align-items: center;
}
&__label {
width: 100px;
flex-shrink: 0;
}
&__text {
flex: 1;
padding-left: 12px;
}
}
</style>
<template>
<div :class="classObj" style="width:480px">
<div class="mk-card__header">标题</div>
<div class="mk-card__content">
<ul class="mk-list">
<li class="mk-list__item" v-for="(item,index) in failedList" :key="index">
<label class="ml-list__label">{{item.name}} :</label>
<span class="mk-list__text">{{item.score}}</span>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'MkCard',
data() {
//这里存放数据
return {
cardType: 'primary',
isShadow: true,
addNum: 1,
list: [
{
name: '张三',
score: 90,
},
{
name: '李四',
score: 86,
},
{
name: '王五',
score: 50,
},
],
}
},
//监听属性 类似于data概念
computed: {
//依赖响应式数据,返回最终计算结果
classObj() { //该函数为get函数,必须有返回值
return {
'mk-card': true,
['mk-card--' + this.cardType]: this.cardType,
'is-shadow': this.isShadow,
}
},
//作为过滤器使用
failedList() {//该函数为get函数,必须有返回值
return this.list.filter(({ score }) => {
return score < 60
})
},
},
}
</script>
- 计算属性传参
计算属性可以通过闭包来传参,当然,这种使用场景使用计算属性比较少,一般都用方法实现了
<template>
<ul class="mk-list">
<li class="mk-list__item" v-for="(item,index) in list" :key="index">
<label class="ml-list__label">{{item.name}} :</label>
<span class="mk-list__text">{{item.score}}----{{commentFormatter(item)}}</span>
</li>
</ul>
</template>
<script>
export default {
name: '',
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
list: [
{
name: '张三',
score: 96,
comment: '优秀',
},
{
name: '李四',
score: 86,
comment: '良好',
}
],
}
},
//监听属性 类似于data概念
computed: {
//计算属性使用闭包传参
commentFormatter() {
return function (item) {
return item.comment
}
},
},
}
</script>
- 计算属性getter 和 setter的使用
计算属性有get 和 set 两个函数,当依赖发生改变时,触发get函数;当计算属性发生改变的时候,触发set函数,在set函数中不能直接修改计算属性,会导致死循环,可修改计算属性相关的依赖值,从而触发get函数,从而引起计算属性的重计算,返回最新计算结果。
<template>
<div class>
<div>
firstName :
<input type="text" v-model="firstName" />
</div>
<div>
lastName :
<input type="text" v-model="lastName" />
</div>
<div>
fullName :
<input type="text" v-model="fullName" />
</div>
</div>
</template>
<script>
export default {
name: '',
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
firstName: 'Foo',
lastName: 'Bar',
}
},
//监听属性 类似于data概念
computed: {
fullName: {
// getter
//当依赖发送改变时会执行
get: function () {
console.log('====fullName get=======' + this.firstName)
return this.firstName + ' ' + this.lastName
},
// setter
//当计算属性发生改变时触发
set: function (newValue) {
console.log('====fullName set=======' + newValue)
var names = newValue.split(' ')
//修改计算属性相关的依赖属性值
this.firstName = names[0]
this.lastName = names[names.length - 1]
},
},
},
}
</script>
- 计算属性的cache缓存属性;默认为true(开启缓存)
computed 默认缓存计算值,当cache设置为false时,每次调用会重新计算属性值
<template>
<div class></div>
</template>
<script>
export default {
data() {
//这里存放数据
return {}
},
//监听属性 类似于data概念
computed: {
now: {
cache: true,
get: function () {
return Date.now()
},
},
},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
setInterval(() => {
// 当缓存开关为false的时候,定时器每次打印的时间都是不一样的
console.log(this.now)
}, 1000)
},
}
</script>
案例中,Date.now()是个可变值,但非响应式依赖,即便是变化,也不会触发set重新计算,每次会返回首次计算的值;当设置cache: false时,则不缓存值,每次调用重新计算
==*注意 :如果不希望用缓存,建议使用方法代替,因为计算属性性能开销比较大,需遍历相关依赖,若无缓存,将不可避免多次执行计算属性的getter *==
watch 侦听器
watch特性
- 观察和响应 Vue 实例上的数据变动,执行相应的回调
- watch回调中可执行任何逻辑,可执行异步任务,
- watch侦听器由handler方法、immediate、deep属性组成
watch的使用
- 常规用法
watch 简写情况下只需传入handle方法
<template>
<div>
<div>
实时搜索 :
<input type="text" v-model="searchInfo" />
</div>
</div>
</template>
<script>
export default {
name: 'Test',
data() {
//这里存放数据
return {
searchInfo: '',
}
},
//监控data中的数据变化
watch: {
searchInfo: function (newVal, oldVal) { //handle函数
console.log('搜索')
},
},
}
</script>
完整写法 ( 该处只提供变化的代码片段 )
//监控data中的数据变化
watch: {
searchInfo: {
handler: function (val, oldVal) {
console.log('搜索')
},
deep: true,
immediate: false,
},
},
- watch 中handle回调函数使用
可传入对应的方法名
//监控data中的数据变化
watch: {
searchInfo: 'toSearch',
},
//方法集合
methods: {
toSearch() {
console.log('搜索')
},
},
可传入回调数组
//监控data中的数据变化
watch: {
searchInfo: [
function handle1(newVal, oldVal) {
console.log('===========handle1')
},
function handle2(newVal, oldVal) {
console.log('===========handle2')
},
'toSearch',
],
},
//方法集合
methods: {
toSearch() {
console.log('搜索')
},
},
可执行异步任务
//监控data中的数据变化
watch: {
searchInfo: function (newVal, oldVal) { //handle函数
setTimeout(() => {
console.log('搜索')
}, 500)
},
},
==*注意 :不应该使用箭头函数来定义 watcher 函数,理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例 *==
- immediate 的用法
默认为fasle,设置为true时,handle回调将会在侦听开始之后被立即调用
watch: {
searchInfo: {
handler: function (newVal, oldVal) {
console.log('搜索')
},
immediate: true,
},
},
- deep的用法
默认情况下,handler 只监听属性引用的变化,只监听了一层,但改变对象内部的属性是监听不到的。因此只有赋值,引用地址发生变化的时候才会被监听
<template>
<div>
<div>
实时搜索 :
<input type="text" v-model="searchInfo" />
</div>
<div>
名称 :
<!-- watchObj内部属性发送改变,但引用地址未发生改变,不会触发侦听器监测 -->
<input type="text" v-model="watchObj.name" />
<button @click="assignment">重新赋值</button>
</div>
</div>
</template>
<script>
export default {
data() {
//这里存放数据
return {
watchObj: {
name: '张三',
sex: '男',
age: 36,
},
}
},
//监控data中的数据变化
watch: {
watchObj: {
handler: function (newVal, oldVal) {
console.log('变化')
},
deep: true,
},
},
//方法集合
methods: {
assignment() {
//赋值后,引用地址发生改变,触发watchObj 侦听器监测
this.watchObj = {
name: '张三',
sex: '男',
age: 36,
}
},
},
}
</script>
当deep设置为true的时候,监听器会往下层依次遍历,给所有的属性执行 getter/setter,因此,对象或数组任何属性发生改变会触发对应的监听
watch: {
watchObj: {
handler: function (newVal, oldVal) {
console.log('变化')
},
deep: true,
},
},
- 监听对象的某个属性变化
watch: {
'watchObj.name': function (newVal, oldVal) {
console.log('name变化')
},
},
- 监听多个值变化
当需要监听多个值变化触发相关业务逻辑的时候,给每个值增加监听器,会出现多次监听,触发多次业务方法,这个时候可以结合计算属性
computed、watch、methods的对比
名称 | 特点 | 应用场景 |
---|---|---|
computed | 1、基于响应性依赖来进行计算,具有缓存性 2、具有 get/set两个属性函数 3、必须同步执行,不能执行异步任务 | 1、适用于一些重复使用数据或复杂的运算,具体缓存性 2、所需数据依赖于其他的数据 |
watch | 1、观察和响应 Vue 实例上的数据变动,执行相应的回调 2、回调中可执行任何逻辑,可执行异步任务 3、watch侦听器由handler方法、immediate、deep属性组成 | 1、数据变化时执行异步或开销较大的操作 |
methods | 1、不具备缓存性 2、可执行异步任务 | 很广泛 |
如果觉得这篇文章有用,就给颗小心心哟!