3

4.计算属性

本节要实现的功能超级简单,字符串反转:

clipboard.png

js 实现

js 实现字符串反转还是蛮简单的:

"你好,Vue".split('').reverse().join(''); // 先分割成数组,再反转数组,然后再拼接成字符串

完整版如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/vue/2.2.6/vue.js"></script>
    
</head>
<body>
    <div id="root">
        <h1>{{message}}</h1>
    </div>

    <script>

        let data = {
            _message: "你好,Vue"
        };

        Object.defineProperty(data, 'message', { 
            enumerable:true,
            get: function() { 
                return this._message.split('').reverse().join('');
            } 
        });


        var vm = new Vue({
            el: '#root',
            data:data
        })
    </script>
</body>
</html>

我们采用动态添加属性的方式来动态添加 message 变量。但是,Vue 是不能识别动态添加的属性的,因此,我们要设置该属性的可枚举属性 enumerabletrue

vue 实现

现在,来看看 vue 如何实现该功能:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/vue/2.2.6/vue.js"></script>
    
</head>
<body>
    <div id="root">
        <h1>{{reversedMessage}}</h1>
    </div>

    <script>

        let data = {
            message: "你好,Vue"
        };

        var vm = new Vue({
            el: '#root',
            data:data,
            computed:{
                reversedMessage: function() {
                    return this.message.split('').reverse().join('');
                }
            }
        })
    </script>
</body>
</html>

我们使用了计算属性来实现。在 computed 中声明了一个计算属性 reversedMessage,在里面定义了反转字符串的方法,这将作用于 vm.reversedMessagegetter。该过程和我们刚才用 defineProperty 来定义属性的 getter 还有点相似呢。

细心的人会发现,使用方法也是可以实现的:

<div id="root">
    <h1>{{reversedMessage()}}</h1>

</div>

<script>

    let data = {
        message: "你好,Vue"
    };

    var vm = new Vue({
        el: '#root',
        data:data,
        methods:{
            reversedMessage: function() {
                return this.message.split('').reverse().join('');
            }
        }
    })
</script>

那么,计算属性和方法有什么区别呢?在这个例子,是看不出区别的。

属性 VS 方法

我们来看下面的例子:

<div id="root"></div>

<script>

    let data = {
        message: "你好,Vue"
    };

    var vm = new Vue({
        el: '#root',
        data:data,
        methods:{
            method_now(){
                return Date.now();
            }
        },
        computed:{
            computed_now: function () {
                return Date.now();
              }
        }
    })
</script>

在控制台中进行比较:

clipboard.png

可以看出,methods 每次都会重新计算,而 computed 则会依赖于缓存,除非 computed` 依赖的值发生变化,否则直接调用缓存。

任务表显示

另外,使用计算属性可以让我们的代码可读性更高一些,例如,我们显示未完成的任务列表,通常会想到这样做:

<div id="root">
    <h1>全部任务</h1>
     <ul>
         <li v-for="task in tasks">{{task.description}}</li>
     </ul>

     <h1>未完成的任务</h1>

     <ul>
         <li v-for="task in tasks" v-if="task.uncompleted">{{task.description}}</li>
     </ul>
</div>

<script>

    let data = {
        tasks:[
            {description:"编程",uncompleted:true},
            {description:"锻炼",uncompleted:false},
            {description:"阅读",uncompleted:true},
            {description:"睡觉",uncompleted:false}

        ]        
    };

    var vm = new Vue({
        el: '#root',
        data:data,
    })
</script>

如果使用计算属性,可以使可读性更强,同时还可以再多个地方复用:

<div id="root">
    <h1>全部任务</h1>
     <ul>
         <li v-for="task in tasks">{{task.description}}</li>
     </ul>

     <h1>未完成的任务</h1>

     <ul>
         <li v-for="task in umcompletedtasks">{{task.description}}</li>
     </ul>
</div>

<script>

    let data = {
        tasks:[
            {description:"编程",uncompleted:true},
            {description:"锻炼",uncompleted:false},
            {description:"阅读",uncompleted:true},
            {description:"睡觉",uncompleted:false}

        ]        
    };

    var vm = new Vue({
        el: '#root',
        data:data,
        computed:{
            umcompletedtasks: function(){
                return this.tasks.filter(function(){
                    return task.uncompleted;
                });
            }
        }
    })
</script>

参考:


心智极客
1k 声望645 粉丝