• 3. Vue语法--计算属性


    一. 计算属性

    1. 什么是计算属性?

    通常, 我们是在模板中, 通过插值语法显示data的内容, 但有时候我们可能需要在{{}}里添加一些计算, 然后在展示出来数据. 这时我们可以使用到计算属性

    先来举个例子, 比如: 一个班, 有几个学生参加期末考试, 要计算考试的平均分. 我们来看看, 通常要怎么做?

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">考试成绩
        <ul>
            <li v-for="stu in students">{{stu.name}} -- {{stu.score}}</li>
        </ul>
    
        <p>平均分: <label>{{getAvg()}}</label></p>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message:"班级考试平均分",
                students: [
                    {name:"张三", score:90},
                    {name:"lisi", score:100},
                    {name:"wangwu", score:99},
                    {name:"zhaoliu", score:89},
                    {name:"liuqi", score:95}
                ]
            },
            methods: {
                getAvg() {
                    let sum = 0;
                     for (let i = 0; i < this.students.length; i++) {
                         console.log(this.students[i].score);
                         let stu = this.students[i];
                         sum += stu.score;
                     }
                     console.log("平均分:" + sum/this.students.length);
                     return sum/this.students.length;
                }
            }
        })
    </script>
    </body>
    </html>

    我们定义了一组学生的成绩. 然后将其显示在页面上, 然后通过方法getAvg计算平均分. 

     这里我们在获取平均分的时候, 使用的是{{getAve()}} 其实, 平均分我们理解更像是一个属性, 而不是一个方法. 为了方便计算, vue给我们提供了一个computed属性, 专门用来做计算. computed中定义的也是方法, 这个方法的方法名通常都定义为名词. 我们来看一下使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">考试成绩
        <ul>
            <li v-for="stu in students">{{stu.name}} -- {{stu.score}}</li>
        </ul>
    
        <p>平均分: <label>{{avg}}</label></p>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message:"班级考试平均分",
                students: [
                    {name:"zhangsan", score:90},
                    {name:"lisi", score:100},
                    {name:"wangwu", score:99},
                    {name:"zhaoliu", score:89},
                    {name:"liuqi", score:95}
                ]
            },
            computed: {
                avg: function() {
                    let sum = 0;
                    for (let i = 0; i < this.students.length; i++) {
                        console.log(this.students[i].score);
                        let stu = this.students[i];
                        sum += stu.score;
                    }
                    console.log("平均分:" + sum/this.students.length);
                    return sum/this.students.length;
                }
            },
            methods: {
    
            }
        })
    </script>
    </body>
    </html>

    这里,增加了一个computed属性, 里面定义了avg方法, 没错, 本质还是方法, 但命名的时候, 将其命名为名词.

    眼尖的同学应该已经发现了, 这好像和methods方法一样啊, 就是换了个名字. 那computed计算属性和methods方法有什么区别呢?

    2. 计算属性computed的缓存功能

    我们用案例来说明他们之间的区别. 

    案例1. methods方法

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <p> Origin Message: {{message}}</p>
        <p>Mthod Message:{{getMessage()}}</p>
        <p>Mthod Grade:{{getGrade()}}</p>
        <p>Mthod Class:{{getClass()}}</p>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message:"班级考试平均分",
                className: "1班",
                gradeName:"一年级"
            },
            methods: {
                getGrade: function(){
                    console.log("调用Grade计算")
                    return "方法" + this.gradeName
                },
                getClass: function(){
                    console.log("调用class计算")
                    return "方法" + this.className
                },
                getMessage: function(){
                    console.log("调用message计算")
                    return "方法" + this.message
                }
            }
        })
    </script>
    </body>
    </html>

     我们发现, 在修改一个属性, 其他属性都没变化的情况下, 我们发现methods里的方法都被执行了一遍

     案例2. computed计算属性

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <p> Origin Message: {{message}}</p>
        <p>Mthod Message:{{getMessage}}</p>
        <p>Mthod Grade:{{getGrade}}</p>
        <p>Mthod Class:{{getClass}}</p>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message:"班级考试平均分",
                className: "1班",
                gradeName:"一年级"
            },
            computed: {
                getGrade: function(){
                    console.log("调用Grade计算")
                    return "方法" + this.gradeName
                },
                getClass: function(){
                    console.log("调用class计算")
                    return "方法" + this.className
                },
                getMessage: function(){
                    console.log("调用message计算")
                    return "方法" + this.message
                }
            }
        })
    </script>
    </body>
    </html>

    控制台输出

     

     我们发现, 当控制台修改其中一个属性值, 只有调用这个属性的方法会重新执行

    案例3:  再看一个computed缓存的例子

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <p>调用方法</p>
        <p>{{getMes()}}</p>
        <p>{{getMes()}}</p>
        <p>{{getMes()}}</p>
        <p>{{getMes()}}</p>
    
    
        <p>调用计算属性</p>
        <p>{{mes}}</p>
        <p>{{mes}}</p>
        <p>{{mes}}</p>
        <p>{{mes}}</p>
    
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                firstName: "Elon",
                lastName: "Musk"
            },
            computed: {
                mes: function(){
                    console.log("调用计算属性")
                    return this.firstName + " " + this.lastName
                }
            },
            methods: {
                getMes: function(){
                    console.log("调用method方法")
                    return  this.firstName  + " " +  this.lastName
                }
            }
        })
    </script>
    </body>
    </html>

    这是两种方式的调用, 但是结果都一样, 都是打印输出姓名, 计算属性mes调用了四次, 方法getMes()也调用了四次, 我们来看看运行结果

     两次打印的结果是一样的, 但是调用getMes()调用了4次, 而mes计算属性只计算了一次.

    总结

    • methods方法和computed计算属性,两种方式的最终结果确实是完全相同
    • 不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值,多次访问getMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
    • methods方法,每当触发重新渲染时,调用方法将总会再次执行函数。

    所以,官网说,对于任何复杂逻辑,都应当使用计算属性。

    3. 计算属性的getter和setter访问器

    问题: 我们发现, 在计算属性和methods方法调用的是偶还有一点不同, 那就是调用方式不同. method方调用是{{getMessage()}}, 而计算属性是{{getMessage}}, 我们上面不是说计算属性中定义的也是方法么? 为什么不需要使用()呢? 下面来研究一下

    还是这个案例, 我们来看看代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">{{message}} {{avg}}</div>
    
    <script src="../js/vue.js"></script>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                message: "计算平均分:",
                students: [
                    {name:"zhangsan", score:90},
                    {name:"lisi", score:100},
                    {name:"wangwu", score:99},
                    {name:"zhaoliu", score:89},
                    {name:"liuqi", score:95}
                ]
            },
            computed: {
                avg: function() {
                    let sum = 0;
                    for (let i = 0; i < this.students.length; i++) {
                        console.log(this.students[i].score);
                        let stu = this.students[i];
                        sum += stu.score;
                    }
                    console.log("平均分:" + sum/this.students.length);
                    return sum/this.students.length;
                }
              
            }
        });
    </script>
    </body>
    </html>

     我们在计算平均分的时候, 是把avg当做一个属性来对待的, 所以,调用的时候这么写{{avg}}, 而不是{{avg()}}. 但是我们定义的时候却是给定义成方法了, 为什么会这样呢?

    下面我们来研究computed完整的写法, 研究完这个, 就知道为什么这么写了. 

    • 其实计算属性本身是定义为了一个属性. 例如: 我们定义test, 通常我们定义属性是这么定义的
    test: "这是一个属性"
    • 在计算属性里, 属性值是一个对象, 所以, 我们要这么定义
    computed: {
        test: {
    
        }
    }
    • 对象的内部有两个方法, 一个是get方法, 一个是set方法. 这时在get方法中return一个abc, 这是, 在页面显示的就应该是abc
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">{{message}} --- {{avg}} --- {{test}}</div>
    
    <script src="../js/vue.js"></script>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                message: "计算平均分:",
                students: [
                    {name:"zhangsan", score:90},
                    {name:"lisi", score:100},
                    {name:"wangwu", score:99},
                    {name:"zhaoliu", score:89},
                    {name:"liuqi", score:95}
                ]
            },
            computed: {
                avg: function() {
                    let sum = 0;
                    for (let i = 0; i < this.students.length; i++) {
                        console.log(this.students[i].score);
                        let stu = this.students[i];
                        sum += stu.score;
                    }
                    console.log("平均分:" + sum/this.students.length);
                    return sum/this.students.length;
                },
                test : {
                    set: function(newValue) {
                        this.message = newValue;
                        console.log("调用setter")
                    },
                    get: function() {
                        return "abc" 
                    }
                }
            }
        });
    </script>
    </body>
    </html>

    看看效果

    确实打印输出了abc

    • 因为有get方法和set方法, 所以, 我们可以修改test的值,  如下: 修改了app.test的值, 最终改变了message的值.

     

    • 然而, 计算属性通常只实现get方法, 而不实现set方法. 我们是计算后输出, 而不允许北外不修改,  这时计算属性就只剩下一个get方法, 最后我们将其简写, 去掉get, 就是我们通常看到的写法
    computed: {
        avg: function() {
            let sum = 0;
            for (let i = 0; i < this.students.length; i++) {
                console.log(this.students[i].score);
                let stu = this.students[i];
                sum += stu.score;
            }
            console.log("平均分:" + sum/this.students.length);
            return sum/this.students.length;
        },
        avg1 : function() {
                return "abc" 
            
        }
    }

    虽然写法和method差不多. 但本质上, 计算属性还是属性, 所以, 和属性的写法是一样的.

    as



  • 相关阅读:
    Beta 冲刺 (2/7)
    福大软工 · 第十次作业
    Beta 冲刺(1/7)
    BETA 版冲刺前准备
    福大软工 · 第十一次作业
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    2017-2018-1 20155321 《信息安全系统设计基础》第十四周学习总结
    2017-2018-1 20155321 《信息安全系统设计基础》实验五——实时系统
  • 原文地址:https://www.cnblogs.com/ITPower/p/14418949.html
Copyright © 2020-2023  润新知