一,计算属性
1.1什么是计算属性
计算属性需要定义在computed选项中。当计算属性以来的数据发生变化时,这个属性的值会自动更新,所有依赖该属性的数据绑定也会同步进行更新
在一个计算属性中可以实现各种复杂的罗伊,包括运算,函数调用等。示例代码如下
<div id="app">
<p>原字符串:{{str}}</p>
<p>新字符串:{{newstr}}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
str: 'HTML*JavaScript*Vue.js'
},
computed: {
newstr: function () {
return this.str.split('*').join('+');//对字符串进行分割并重新连接
}
},
methods: {}
})
</script>
运行结果如图
上述代码中定义了一个计算属性newstr, 并在模板中绑定了该计算属性。newstr 属性的值依赖于str属性的值。当str属性的值发生变化时,newstr 属性的值也会自动更新。
除了上述简单的用法,计算属性还可以依赖Vue实例中的多个数据,只要其中任一数据发生变化,计算属性就会随之变化,视图也会随之更新。
例:应用计算属性统计购物车中的上品总价,代码如下:
<!DOCTYPE html>
<html lang="en">
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<head>
<meta charset="UTF-8">
<title>统计商品总价</title>
<style>
body {
font-family: 微软雅黑;
font-size: 14px
}
.title {
background: #f6f6f6;
font-size: 18px;
}
.title,
.content {
width: 400px;
height: 36px;
line-height: 36px;
border: 1px solid #dddddd;
}
.title:not(:first-child),
.content {
border-top: none;
}
.title div {
width: 100px;
text-align: center;
float: left
}
.content {
clear: both
}
.content div {
width: 100px;
text-align: center;
float: left
}
p {
width: 380px;
text-align: right;
}
</style>
<script src="../JS/vue.js"></script>
</head>
<body>
<div id="example">
<div class="title">
<div>商品名称</div>
<div>单价</div>
<div>数量</div>
<div>金额</div>
</div>
<div class="content" v-for="value in shop">
<div>{{value.name}}</div>
<div>{{value.price | twoDecimal}}</div>
<div>{{value.count}}</div>
<div>{{value.price*value.count | twoDecimal}}</div>
</div>
<p>合计:{{totalprice | formatPrice("¥")}}</p>
</div>
<script type="text/javascript">
var exam = new Vue({
el: '#example',
data: {
shop: [{//定义商品信息数组
name: 'OPPO R15',
price: 2999,
count: 3
}, {
name: '华为P20',
price: 3699,
count: 2
}]
},
computed: {
totalprice: function () {
var total = 0;
this.shop.forEach(function (s) {
total += s.price * s.count;//计算商品总价
});
return total;
}
},
filters: {
twoDecimal: function (value) {
return value.toFixed(2);//保留两位小数
},
formatPrice: function (value, symbol) {
return symbol + value.toFixed(2);//添加人民币符号并保留两位小数
}
}
})
</script>
</body>
</html>
运行结果如图所示:
1.2getter和setter
每一个计算属性都包括一个getter和一个setter。当没有指明方法时,默认使用getter来读取数据。示例代码如下:
<div id="app">
<p>姓名:{{fullname}}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
surname: '韦',
name: '小宝'
},
computed: {
fullname: function () {
return this.surname + this.name;//连接字符串
}
}
,
methods: {}
})
</script>
运行结果如下:
上述代码中定义了一个计算属性sum,为该属性提供的函数将默认作为sum属性的getter,因此,上述代码也可以写成如下代码:
<div id="app">
<p>姓名:{{fullname}}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
surname: '韦',
name: '小宝'
},
computed: {
fullname: {
//getter
get: function () {
return this.surname + this.name;//连接字符串
}
}
}
,
methods: {}
})
</script>
除了getter,还可以设置计算属性的setter。getter用来执行读取值的操作,而setter用来执行设置值的操作。当手动更新计算属性的值时,就会触发setter,执行一些自定义的操作。示例代码如下:
<div id="app">
<p>姓名:{{fullname}}</p>
</div>
<script>
var exam = new Vue({
el: '#app',
data: {
surname: '韦',
name: '小宝'
},
computed: {
fullname: {
//getter
get: function () {
return this.surname + this.name;//连接字符串
},
// setter
set: function (value) {
this.surname = value.substr(0, 1);
this.name = value.substr(1)
}
}
}
,
})
exam.fullname = '张无忌'
</script>
运行结果如图:
上述代码中定义了一个计算属性fullname, 在为其重新赋值时,Vue.js会自动调用setter,并将新值作为参数传递给set()方法,surname属性和name属性会相应进行更新,模板中绑定的fullname属性的值也会随之更新。如果在未设置setter的情况下为计算属性重新赋值,是不会触发模板更新的。
1.3计算属性缓存
通过上面的示例可以发现,除了使用计算属性外,在表达式中调用方法也可以实现同样的效果。使用方法实现同样效果的示例代码如下:
<div id="app">
<p>姓名:{{fullname()}}</p>
</div>
<script>
var exam = new Vue({
el: '#app',
data: {
surname: '韦',
name: '小宝'
},
methods: {
fullname: function () {
return this.surname + this.name
}
}
})
</script>
将相同的操作定义为一个方法, 或者定义为一个计算属性,两种方式的结果完全相同。然而,不同的是计算属性是基于它们的依赖进行缓存的。使用计算属性时,每次获取的值是基于依赖的缓存值。当页面重新渲染时,如果依赖的数据未发生改变,使用计算属性获取的值就一直是缓存值。只有依赖的数据发生改变时才会重新执行getter。
下面通过一个示例来说明计算属性的缓存。代码如下:
<div id="app">
<input v-model="message">
<p>{{message}}</p>
<p>{{getTimeC}}</p>
<p>{{getTimeM()}}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: '',
time: '当前时间:'
},
computed: {
getTimeC: function () {
var hour = new Date().getHours();
var minute = new Date().getMinutes();
var second = new Date().getSeconds();
return this.time + hour + ':' + minute + ':' + second;
}
},
methods: {
getTimeM: function () {
var hour = new Date().getHours();
var minute = new Date().getMinutes();
var second = new Date().getSeconds();
return this.time + hour + ':' + minute + ':' + second;
}
}
})
</script>
运行上述代码,在页面中会输出一个文本框,以及分别通过计算属性和方法获取的当前时间,结果如图1所示。在文本框中输入内容后,页面进行了重新谊染,这时,通过计算属性获取的当前时间是缓存的时间,而通过方法获取的当前时间是最新的时间。结果如图2所示。
在该示例中,getTimeC 计算属性依赖于time属性。当页面重新谊染时,只要time属性未发生改变,多次访问getTimeC计算属性会立即返回之前的计算结果,而不会再次执行函数,因此会输出缓存的时间。相比之下,每当触发页面重新谊染时,调用getTimeM()方法总是会再次执行函数,因此会输出最新的时间。
图一:
图二: