computed

作者: zsyyyyy | 来源:发表于2019-07-14 21:50 被阅读0次
    <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打印一下也行

相关文章

网友评论

      本文标题:computed

      本文链接:https://www.haomeiwen.com/subject/ssepkctx.html