【猿说VUE】如影相随,VUE计算属性和监视

VUE计算属性和监视

5.1 计算属性

Vue中会有部分数据经常依赖于别的数据的改变而做出改变,并且变化逻辑也较复杂,这个时候就需要用到计算属性:computed,也就是说对于当前数据是不确定的,要经常因为其他数据改变而同时做出改变。

  • computed属性对象中定义计算属性的方法
  • 在HTML页面中使用{{ methodName }} 来显示计算的结果

5.1.1 Why Computed

还是先通过官方的例子来说明一下为什么要使用computed。从第四章内容可以看出在模板内的使用表达式非常便利,但是,当我们的表达式中放入太多逻辑,就会导致模板语法越来越复杂,不利于理解,难于维护。

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

在如上的模板代码中,需要花费时间去理解,这段代码究竟想要渲染什么?message的翻转字符串。然而,模板表达式的初衷是为了简单运算的,因此就不建议在模板中使用过于复杂的表达式。因此,计算属性就借机横空出世。计算属性就是当依赖的属性的值发生变化的时候,才会触发它的改变,如果依赖的值,没有发生变化的时候,使用的是缓存中的属性值。

Computed示例代码:

  <div id="app">
    <p>原始字符:“{{ msg }}”</p>
    <p>反转字符:“{{ reversedMsg }}”</p>
  </div>


  <script type="text/javascript">
	const vm = new Vue ({
      el: '#app',
      data: {
        msg: 'Hello Vue!'
      },

      // 计算属性: 值为对象
      computed: {
        reversedMsg: function() {  // 属性的getter
            // this 指代VM实例
            return this.msg.split('').reverse().join('');
        }
    })          
  </script>

上面的例子中我们做成的计算属性的函数将用作属性 vm.reversedMsggetter函数。我们在Chrome浏览器控制台,直接修改vm.msgvm.reversedMsg 的值始终根据最新vm.message 的值来重新计算。

5.1.2 computed VS methods

  • 可以使用 methods 来替代computed,使用效果上两者一样。
  • computed是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值,所以相对性能会更好。如果不希望缓存,建议使用 methods 属性。
  • methods在重新渲染的时候,函数总会重新调用执行。

应用说明:computed比较适合对多个变量进行逻辑处理,最后返回一个处理结果。当多个变量中的任何一个值发生了变化则我们监控的这个值也就会发生变化。例如:购物车的商品列表的总金额,当商品列表里面的商品数量发生变化或者单价因为促销发生改变,总金额都会随之发生变化。此时的总金额就非常适合使用computed属性来进行计算。假想一个场景,对于性能开销比较大的的计算属性One(例如商品列表的总金额),需要遍历一个极大的数组和做大量的计算,另外,可能有其他的计算属性依赖于One。如果没有缓存,我们将不可避免的多次执行One 的getter,会导致性能下降。

5.1.3 计算属性:getter & setter

vue中,computed的属性可以被视为是data一样,可以读取和设值,即在computed中可以分为gettersetter。默认情况下computed是没有setter的,computed只是预设了getter,也就是只能读取,不可以改变设值。

vue中当需要赋值给计算属性的时候,将调用setter函数。多用于在模板组件中需要修改计算属性自身的值的时候。只有当计算属性中的属性被直接赋值的时候,才会走setter函数。注意:settergetter是相互独立的。

<script type="text/javascript">
    const vm = new Vue ({
      el: '#app',
      data: {
        msg: 'Hello Vue!',
        firstName: 'gavin',
        lastName: 'bj',
        fullName: 'gavin-bj'
      },

      computed: {  // 计算属性: 值为对象
        reversedMsg () {
            // this 指代VM实例
            return this.msg.split('').reverse().join('');
        },

        fullNameDefault() { // computed属性默认的getter
          console.log('fullNameDefault()', this)
          return this.firstName + '-' + this.lastName
        },

        fullNameTwoWay: {
          // 当获取当前属性值时自动调用, 将返回值(根据相关的其它属性数据)作为属性值
          get() {
            console.log('fullNameTwoWay get()')
            return this.firstName + '-' + this.lastName
          },
          // 当属性值发生了改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
          set(value) { // fullNameTwoWay的最新value值  A-B23
            console.log('fullNameTwoWay set()', value)
            // 更新firstName和lastName
            const names = value.split('-')
            this.firstName = names[0]
            this.lastName = names[1]
          }
        }
      }
    })
  </script>

5.2 监听属性

接下来说明一下Vue.js的监听属性:watch。可以通过 watch 来响应数据的变化。也可以通过命令式的vm.$watch来监视指定的属性。建议是使用计算属性而不是命令式的 watch 回调函数。

  <div id="app">
    <h2>Computed默认使用:</h2>
    <p>原始字符:“{{ msg }}”</p>
    <p>反转字符:“{{ reversedMsg }}”</p>
    <hr>
    <p>姓:<input type="text" placeholder="First Name" v-model="firstName"></p>
    <p>名:<input type="text" placeholder="Last Name" v-model="lastName"></p>

    <h2>Computed属性说明</h2>
    <p>
        显示全名A(单向):<input type="text" placeholder="Full Name" v-model="fullNameDefault"><br>
        显示全名B(监听):<input type="text" placeholder="Full Name" v-model="fullName"><br>
        显示全名C(双向):<input type="text" placeholder="Full Name" v-model="fullNameTwoWay"><br>
    </p>
    <p>{{fullNameDefault}}</p>
    <p>{{fullName}}</p>
    <p>{{fullNameTwoWay}}</p>

  </div>

  <script type="text/javascript">
    const vm = new Vue ({
      el: '#app',
      data: {
        msg: 'Hello Vue!',
        firstName: 'gavin',
        lastName: 'bj',
        fullName: 'gavin-bj'
      },

      computed: {  // 计算属性: 值为对象
        reversedMsg () {
            // this 指代VM实例
            return this.msg.split('').reverse().join('');
        },

        fullNameDefault() { // computed属性默认的getter
          console.log('fullNameDefault()', this)
          return this.firstName + '-' + this.lastName
        },

        fullNameTwoWay: {
          // 获取属性值时自动调用, 将返回值作为属性值
          get() {
            console.log('fullNameTwoWay get()')
            return this.firstName + '-' + this.lastName
          },
          // 当属性值改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
          set(value) { // fullNameTwoWay的最新value值
            console.log('fullNameTwoWay set()', value)
            // 更新firstName和lastName
            const names = value.split('-')
            this.firstName = names[0]
            this.lastName = names[1]
          }
        }
      },

      watch: {
        // 配置监视firstName
        firstName: function (value) { // 相当于属性的set
          console.log('watch firstName', value)
          // 更新fullName
          this.fullName = value + '-' + this.lastName
        }
      }
    })

    // 使用命令式的vm.$watch API来监视lastName, 等同于侦听器
    vm.$watch('lastName', function (value) {
      console.log('$watch lastName', value)
      // 更新fullName
      this.fullName = this.firstName + '-' + value
    })
  </script>

5.3 完整代码

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>N003:计算属性和监视</title>
</head>

<body>
  <div id="app">
    <h2>Computed默认使用:</h2>
    <p>原始字符:“{{ msg }}”</p>
    <p>反转字符:“{{ reversedMsg }}”</p>
    <hr>
    <p>姓:<input type="text" placeholder="First Name" v-model="firstName"></p>
    <p>名:<input type="text" placeholder="Last Name" v-model="lastName"></p>

    <h2>computed属性默认的getter</h2>
    <p>
        显示全名A(单向):<input type="text" placeholder="Full Name" v-model="fullNameDefault"><br>
        显示全名B(监听):<input type="text" placeholder="Full Name" v-model="fullName"><br>
        显示全名C(双向):<input type="text" placeholder="Full Name" v-model="fullNameTwoWay"><br>
    </p>
    <p>{{fullNameDefault}}</p>
    <p>{{fullName}}</p>
    <p>{{fullNameTwoWay}}</p>

  </div>

  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script type="text/javascript">
    const vm = new Vue ({
      el: '#app',
      data: {
        msg: 'Hello Vue!',
        firstName: 'gavin',
        lastName: 'bj',
        fullName: 'gavin-bj'
      },

      computed: {  // 计算属性: 值为对象
        reversedMsg () {
            // this 指代VM实例
            return this.msg.split('').reverse().join('');
        },

        fullNameDefault() { // computed属性默认的getter
          console.log('fullNameDefault()', this)
          return this.firstName + '-' + this.lastName
        },

        fullNameTwoWay: {
          // 当获取当前属性值时自动调用, 将返回值(根据相关的其它属性数据)作为属性值
          get() {
            console.log('fullNameTwoWay get()')
            return this.firstName + '-' + this.lastName
          },
          // 当属性值发生了改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
          set(value) { // fullNameTwoWay的最新value值  A-B23
            console.log('fullNameTwoWay set()', value)
            // 更新firstName和lastName
            const names = value.split('-')
            this.firstName = names[0]
            this.lastName = names[1]
          }
        }
      },

      watch: {
        // 配置监视firstName
        firstName: function (value) { // 相当于属性的set
          console.log('watch firstName', value)
          // 更新fullName
          this.fullName = value + '-' + this.lastName
        }
      }
    })

    // 使用命令式的vm.$watch API来监视lastName, 等同于侦听器
    vm.$watch('lastName', function (value) {
      console.log('$watch lastName', value)
      // 更新fullName
      this.fullName = this.firstName + '-' + value
    })
  </script>
</body>

</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章