vue计算属性

279 阅读5分钟

computed计算属性

  • 作用:用于在data数据被渲染前的操作,有利于逻辑代码和模板的分离。这里指明是data中的数据,因为data中的数据是响应式的。
  • 两种使用方式::
    • 可以在计算属性中直接使用this访问data的数据
    • 使用回调函数的形式接受一个vm实例通过vm实例访问data的属性
  • 注意点:computed中定义的属性名不能和data中的属性名重名,不然警告已经被定义The computed property "categories" is already defined in data.

1. 基本使用

<!-- 示例1:-->
<div id="app">
  <!-- 这种比较繁琐 -->
  {{ this.firstName + ' ' + this.lastName }}
  <!-- 计算属性的方式比较简洁 -->
  {{ fullName }}
</div>
<script>
  new Vue({
    el: '#app',
    data: {
      firstName: 'Nice',
      lastName: 'alice'
    },
    computed: {
      // 通过箭头函数接受vm实例的方式
      fullName: vm => vm.firstName.concat('-').concat(vm.lastName)
    }
  })
</script>
<!-- 示例2: -->
<body>
    <!-- 308 --308  -->
    <div id="app">{{ totalPrice }} -- {{totalPriceTwo}}</div>
    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                categories: [
                    { id: 1, name: '计算机网络', price: 100 },
                    { id: 2, name: '操作系统', price: 98 },
                    { id: 3, name: '深入理解计算机系统', price: 110 },
                ]
            },
           // 通过this的方式
            computed: {
                totalPrice() {
                    return this.categories.reduce((a, b) => {
                        a.price += b.price
                        return a;
                    }, { price: 0 }).price
                },
                totalPriceTwo() {
                    return this.categories.map(item => item.price).reduce((a, b) => a + b);
                },
            },


        });
    </script>
</body>

2. 计算属性本质

  • 计算属性的本质是包含settergetter方法的一个属性,所以在模板中访问的时候不是函数调用的方式,而是像访问data中的属性一样访问计算属性;说白了计算属性跟data中的数据属性一样是属性而不是方法
  • 如果没有自己实现set,那么计算属性默认是只读的,不能更改。
<!-- 示例1:本质写法 -->
<div id="app">{{ fullName }}</div>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      firstName: 'Nice',
      lastName: 'alice'
    },
    computed: {
      // 本质是个包含setter和getter方法的对象; 在访问fullName属性时,会默认调用get函数,并将get函数的返回值作为fullName属性的值
      fullName: {
        set() { },
        get() {
          return this.firstName.concat(' ').concat(this.lastName)
        }
      }
    }
  });
</script>
// 示例2:简写过度阶段
computed: {
  fullName: {
    get() {
        return this.firstName.concat(' ').concat(this.lastName)
    }
  }
}

// 示例3: 简写最终版————因为一般我们不希望别人给我们的计算属性设置值,所以就把set函数删掉了,相当于计算属性是个只读属性;那么计算属性都只有一个get方法,每次都写get方法太麻烦了,所以直接把get省略了
computed: {
  fullName: function{
    return this.firstName.concat(' ').concat(this.lastName)
  }
}
<!-- 示例4:自己实现set函数
// 可以自己实现set方法,实现了set方法就不是只读属性了;
// 备注:自己实现的set方法,set方法是有一个参数的,fullName被赋值时的值就是set的参数
-->

<div id="app">{{ fullName }}</div>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      firstName: 'Nice',
      lastName: 'alice',
    },
    computed: {
      fullName: {
        // 当执行 vm.fullName = 'hello bob'时,就会默认调用set函数,newValue就等于'hello bob'
        set(newValue) {
          var names = newValue.split(' ')
          this.firstName = names[0];
          this.lastName = names[1];
        },
        get() {
          return this.firstName.concat(' ').concat(this.lastName)
        }
      }
    }
  });
</script>

3. 计算属性缓存问题

  • 计算属性的值fullName会被缓存,它只会监听get中使用的data数据项里面的属性(比如data的flag没有被计算属性使用,所以flag的变化不会导致重新计算),如果有变化,则会重新更新计算属性
  • 由于计算属性的值会被缓存,所以多次访问计算属性值只会调用一次get函数;所以计算属性比methods性能更好一点
<body>
    <div id="app">
        <h1>{{this.firstName + ' ' + this.lastName}}</h1>
        <div>
            methods方法调用次数:3次
            <h1>{{getFullName()}}</h1>
            <h1>{{getFullName()}}</h1>
            <h1>{{getFullName()}}</h1>
        </div>
        <div>
            computed属性调用次数:1次
            <h1>{{fullName}}</h1>
            <h1>{{fullName}}</h1>
            <h1>{{fullName}}</h1>
        </div>

    </div>
    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                firstName: 'Nice',
                lastName: 'alice',
                flag: '111',
            },
            computed: {
                fullName: vm => {
                    console.log('fullName');
                    return vm.firstName.concat(' ').concat(vm.lastName)
                }
            },
            methods: {
                getFullName() {
                    console.log('getFullName');
                    return this.firstName.concat(' ').concat(this.lastName)
                }
            }
        });
    </script>
</body>
  • computed和methods的区别
    • computed计算属性值可以缓存,性能更好。(如果方法中有循环,那么使用方法则会每调用一次方法都会进行for循环)
    • computed计算属性本质是一个属性,不是方法;methods定义的时方法
    • computed除了可以使用基本函数的this访问data之外,还提供箭头函数接受参数vm实例的方式访问data数据;methods中的方法不能使用箭头函数的形式
  • 场景选择:将data的数据做一些变化重新展示的情况建议选择computed, 方法和computed都适用的情况下优先选择com

4. 场景

场景1:计算属性没有监听data中的数据,而是直接返回了123,这种情况不会报错,但是当我们在控制台修改vm.lastName值时,也就是改变dta中的值,计算属性fullname也感知不到,所以这种写法没有任何意义。

// 场景1:
<div id="app">
  {{ fullName }}
</div>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      firstName: 'Nice',
      lastName: 'alice'
    },
    computed: {
      fullName() {
        return 123
      }
    }
  })
</script>

场景2:在控制台修改temp变量的值为'hello',此时页面渲染fullName的值不会变化,还是初始的'xxx';但如果fullName中监听的是data中的属性值,那么在控制台中通过vm修改data中的值,此时页面会重新渲染fullName,因为data中的值是响应式的。

// 场景2:
<div id="app">
  <!-- 在控制台修改temp的值,不会触发这里的重新渲染;这里一直保持temp的初始值xxx;因为temp不是响应式属性 -->
  {{ fullName }}
</div>
<script>
  var temp = 'xxx'
  var vm = new Vue({
    el: '#app',
    data: {
      firstName: 'Nice',
      lastName: 'alice'
    },
    computed: {
      fullName() {
        return temp;
      }
    }
  })
</script>

本文使用 mdnice 排版