<body>
<div id="app">
//不需要我们自己去调用
总价:{{prices}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
packages1: [{
name: "i7",
price: 7199,
count: 2
},
{
name: "ipad",
price: 2888,
count: 1
}
],
packages2: [{
name: "apple",
price: 6,
count: 2
},
{
name: "pear",
price: 10,
count: 10
}
]
},
computed: {
//简写,默认调用get,不执行set
prices: function() {
var price = 0;
for (let i = 0; i < this.packages1.length; i++) {
price += this.packages1[i].price * this.packages1[i].count;
}
for (let i = 0; i < this.packages2.length; i++) {
price += this.packages1[i].price * this.packages1[i].count;
}
return price;
}
},
methods: {
},
mounted: function() {
}
})
</script>
</body>
每个计算属性都包含 getter setter ,我们上面那个示例都是计算属性的默认用法,只是利用了 geter 来读取。在你需要时,也可以提供 一个setter函数 当手动修改计算属性的值就像修改普通数据那样时,就会触发 setter 函数,执行一些自定义操作 ,例如:
<body>
<div id="app">
姓名 : {{fullName}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
firstName: 'jack',
lastName: 'Green'
},
computed: {
//全写
fullName: {
//getter ,用于读取
get: function() {
return this.firstName + "" + this.lastName;
},
//setter 修改数据时触发,newValue变化后的数据
set: function(newValue) {
var names = newValue.split(",");
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
}
},
methods: {
},
mounted: function() {
//当修改fullName ,就会触发setter函数
this.fullName = "jone Doe";
}
})
//当修改fullName ,就会触发setter函数
app.fullName = "jone Doe";
var str = "jone Doe";
var newarr = str.split(",");
console.log(newarr)
</script>
</body>
计算属性还有两个很实用的小技巧容易被忽略:一是计算属性可以依赖其他计算属性:二是
计算属性不仅可以依赖当前 Vue 实例的数据,还可以依赖其他实例的数据,例如:
<body>
<div id="app1">
</div>
<div id="app2">
{{revertext}}
{{revertext2}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app1 = new Vue({
el: "#app1",
data: {
text: "123,456"
},
});
var app2 = new Vue({
el: "#app2",
computed: {
revertext: function() {
//计算可以依赖其他vue实例的数据
return app1.text.split(",").reverse().join();
},
//依赖其他计算属性
revertext2: function() {
if (this.revertext) {
return '我是依赖其他计算属性的'
}
}
},
methods: {
},
mounted: function() {
}
})
</script>
</body>
computed计算属性缓存
你可能发现调用 methods 里的方法也可以与计算属性起到同样的
作用 ,比如本章上面计算属性示例可以用 methods 改写:
<body>
<div id = "app2">
<!-- 注意,这里的revertext是方法,而不是计算属性,所以要带() -->
{{revertext()}}//method每次刷新都调用
{{now}}//当依赖值发生变化才会调用
{{a}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app2 = new Vue({
el: "#app2",
data:{
text:"123,456"
},
computed: {
},
methods: {
//用 methods 改写,因为methods 里写的是方法,所以调用需+()
revertext:function(){
return this.text.split(",").reverse().join();
},
},
computed:{
now:function(){
// Date.now() 方法返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数。
return Date.now();
},
a:function(){
if(this.now){
return "我是依赖其他计算属性的";
}
}
},
mounted: function() {
}
})
</script>
</body>
没有使用计算属性,在 methods 里定义了 个方法实现了相同的效果,甚至该方法还可以接受
参数,使用起来更灵活。既然使用 methods 就可以实现,那么为什么还需要计算属性呢?原因就是
计算属性是基于它的依赖缓存的。 一个计算属性所依赖的数据发生变化时,它才会重新取值,所以
text 只要不改变,计算属性也就不更新,例如上面计算属性now,这里的 Date.now()不是响应式依赖,所以计算属性 now 不会更新。但是 methods 则不同,只要
重新渲染,它就会被调用,因此函数也会被执行
使用计算属性还是 methods 取决于你是否需要缓存,当遍历大数组和做大量计算时,应当使用计算属性,除非你希望得到缓存
当你不想改变原数组,想通过这个数组的副本来做过滤或排序的显示时,可以使用计算属性
来返回过滤或排序后的数组,例如
<div id=” app ” >
<ul>
<template v-for=” book in filterBooks” >
<li>书名 {{book.name }}</li>
<li>作者 {{book author }}</li>
</template>
</ul>
</div>
e643dab1dc49ee807a59a16f0b4e528.png
绑定类名是也可以用computed
<body>
<div id = "app2">
<div :style="styles">文本</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app2 = new Vue({
el: "#app2",
data:{
// styles:{
// color:"yellow",
// fontSize:20+"px"
// }
},
computed: {
styles:function(){
return {
color:"yellow",
fontSize:20+"px"
}
}
},
methods: {
},
mounted: function() {
}
})
</script>
</body>
例子
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#app{
width: 60%;
margin: 10px auto;
}
.inp{
margin-bottom: 30px;
}
.inp input{
width: 30%;
height: 35px;
line-height: 35px;
padding-left: 4px;
}
td{
text-align: center;
}
td span{
cursor: pointer;
}
.total td{
text-align: right;
padding-right: 20px;
}
.selAll{
width: 35px;
height: 35px;
border-radius: 50%;
background: #eee;
cursor: pointer;
text-align: center;
line-height: 35px;
display: inline-block;
margin: 0 3px;
}
</style>
</head>
<body>
<div id="app">
<div class="inp">
<input type="text" v-model.trim="goodsName" placeholder="请输入商品名称" />
<input type="number" v-model.number="goodsPrice" placeholder="请输入价格" />
<button @click="add">添加</button>
</div>
<table border="1" width="100%" cellspacing="0" cellpadding="0">
<tr>
<th><span @click="all" class="selAll">全选</span> 名称</th>
<th>单价(元)</th>
<th>数量</th>
<th>总价(元)</th>
<th>操作</th>
</tr>
<tr v-for="(val,index) in arr">
<td><input v-model="val.isCheck" @change="sel" type="checkbox" /> {{val.name}}</td>
<td>{{val.price}}</td>
<td><span @click="reduce(index)">-</span> {{val.count}} <span @click="plus(index)">+</span></td>
<td>{{(val.price*val.count).toFixed(2)}}</td>
<td @click="del(index)">删除</td>
</tr>
<tr class="total">
<td colspan="5">总价格:{{allPrice}}</td>
<!--<td colspan="5">总价格:{{total.toFixed(2)}}</td>-->
</tr>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
//数据驱动视图
var vm = new Vue({
el:"#app",
data:{
goodsName:"白菜",
goodsPrice:16,
arr:[],
obj:{},
total:0
},
methods:{
add(){//增加条目
this.obj = {
isCheck:false,
name:this.goodsName,
price:this.goodsPrice,
count:1,
totalPrice:1*parseInt(this.goodsPrice)
}
vm.$set(vm.arr,vm.arr.length,vm.obj);
},
reduce(index){//减少商品数量
if(this.arr[index].count>0){
this.arr[index].count--;
this.sel();
}
},
plus(index){//增加商品数量
this.arr[index].count++;
this.sel();
},
del(index){//删除条目
this.arr.splice(index,1);
this.sel();
},
sel(){//计算选择到的商品的总价格
this.total = 0;
for(var i=0;i<this.arr.length;i++){
if(this.arr[i].isCheck){
var {count,price} = this.arr[i];
this.total+=count*price;
}
}
},
all(){//全选
var res = this.arr.every(val=>{
return val.isCheck;
})
this.arr.forEach(val=>{
if(res){
val.isCheck = false;
}else{
val.isCheck = true;
}
})
}
},
computed:{ //计算属性
allPrice(){//计算选中商品的总价格
var total = 0;
for(let i=0;i<this.arr.length;i++){
if(this.arr[i].isCheck){
let {count,price} = this.arr[i];
total += count*price;
}
}
return total.toFixed(2);
}
}
})
</script>
</body>
</html>
<!--//注意该方法不会触发视图更新
//this.arr[this.arr.length] = obj;
/**
* set(targetArr,index,newCont):用于向数组或者对象中添加数据的方法
* targetArr:表示目标数组
* index:表示下标值
* newCont:表示向数组中添加的新元素
* 注意:
* 当使用this(即vue的实例化对象)来调用set方法的时候需要用set的别名$set,
* 当使用Vue构成函数来调用的时候可以直接用set名字。
*
* 以下三种方法实现效果一样。
* */
// this.$set(this.arr,this.arr.length,this.obj);
// Vue.set(vm.arr,vm.arr.length,vm.obj);
// vm.$set(vm.arr,vm.arr.length,vm.obj);-->
vue计算属性无法监听到数组内部变化的解决方案
计算属性可以帮助我们简化代码,做到实时更新,不用再自己添加function去修改data。
首先看一下计算属性的基本写法(摘自官网)
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
这样我们在模版里这样引入computed属性就可以了,他的效果个data一样
<div id="demo">{{ fullName }}</div>
这样我们修改firstName或者lastName,fullName都会同步更新
这里我们主要不是讲这个,而是讲如果把 firstName和lastName放在一个数组里
比如这样[firstName ,lastName]
如果这时候修改数组中的一项会不会有相同的效果呢?
修改一下代码
var vm = new Vue({
el: '#demo',
data: {
nameArray:['Foo' ,'Bar']
},
computed: {
fullName: function () {
return this.nameArray[0] + ' ' + this.nameArray[1]
}
}
})
methods: {
change () {
this.nameArray[0] = '123'
}
触发change方法可见fullName并没有变化。原因可能是vue没有监听到数组 nameArray的长度变化。
此时我们可以采用splice让数组的长度有个变化,这时候vue就可以监听到了
this.nameArray.splice(0, 1, '123')
或者使用vue的$set方法
this.$set(this.nameArray, 0, '123')
还有一点要注意,就是如果这个计算属性没有使用过,也就是说页面中没有引用,也没有其他变量使用他,同样不会触发计算属性。至少,来个console打印一下也行
网友评论