目录

🌓 Vue 计算属性与侦听器 watch

# 计算属性 computed

Vue 中不推荐在模版中使用复杂的表达式,应该重构为「计算属性」或方法;(官网风格指南)

要显示的「属性」不存在时,要通过「已有属性(在 Vue 下管理)」计算得到时可以使用计算属性 computed

  • 原理:底层借助了 Objcet.defineProperty() 方法提供的 gettersetter

    • get 函数什么时候执行?

      • 初次读取时会执行一次(将保存在缓存提供重复使用);
      • 依赖的数据发生改变时会被再次调用;
    • methods 实现相比,内部有缓存机制(复用),效率更高,调试方便

  • ⚠️注意:

    • 最终的计算属性会出现在 vm ,直接读取使用(会自动调用 get )即可;
    • 如果计算属性要被修改,那必须写 set 函数去响应修改,且 set 中要引起计算时依赖的数据发生改变。
  • 使用方法:

    • computed 对象中定义计算属性( get()set() );
    • 在页面中使用 来显示计算的结果;
    • 只读不改的简写,省略 set() 只有 get() 时,直接当计算属性的 get()

🌰 例子:

<div id="#app">
  {{ msg }}
  {{ reversedMsg}}
</div>
1
2
3
4
const vm = new Vue({
  el: "#app",
  data: {
    msg: "Hello"
  },
  computed: {
    reversedMessage: function() {
      return this.message.split('').reverse().join('')
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11

🌰 例子 / setter

(计算属性的完整写法):

computed: {
  fullName: {
    // getter
    get: function() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function() {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

现在设置 fullName 的值时,例如将 vm.fullName = 'John Doe'setter 会被调用,此时 firstNamelastName 也会相应发生改变。

# 侦听器 watch

监听属性)提供了一个更加通用、能够自定义的方法,来相应数据的变化。当需要数据变化时执行异步或者开销较大的操作时,使用 watch 最合适。

当被监视的属性发生变化时,回调函数自动调用进行相关的操作:

  • ⚠️:监视的「属性」必须存在才能进行监视;

  • 监视的两种写法:通过在 new Vue 时传入 watch 配置来监视指定的属性或者通过 vm 对象的 $watch() 监视 ;

  • 监视的 watch(oldValue, newValue) 可以通过参数获取变化的值(旧值和新值);

  • 监视的简写(适用于不需要配置 immediate 等参数);

深度监视

  • Vue 中的 watch 默认不监测对象内部值的改变(一层);
  • 配置 deep: true 可以监测对象内部值的改变;
  • ⚠️注意:
    • Vue 自身可以检测对象的内部值改变,但是 Vue 提供的监视属性 watch 默认不可以;
    • 使用 watch 可以根据数据的具体结构,决定是否采用深度监视;

🌰 例子:

<div id="demo">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>
    {{ answer }}
  </p>
</div>
1
2
3
4
5
6
7
8
9
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

参考自官网的例子。使用 watch 允许执行一个异步操作,限制执行该操作的频率,并且在得到最终结果之前,设置 answer 的中间状态,这些都是 computed 无法做到的。

# 使用监视与计算属性对比

  • computed 能完成时, watch 都能完成:当 watchcomputed 都能实现时,首选用 computed 提高性能;
  • watch 能完成的功能, computed 不一定完成:当时需要实现一些异步功能(例如延时显示)时,就使用 watchcomputed 依靠 return 获取值)

🌰 例子:

<div id="app">
  {{ fullName }}
</div>
1
2
3
const vm = new Vue({
	el: "#app",
  data: {
    firstName: 'foo',
    lastName: 'bar',
    fullName: 'foo bar'
  },
  watch: {
    firstName: function(value) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function(value) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

通过监视属性 watch 侦听 firstNamelastName 的变化,修改 fullName 的值。但是两个代码逻辑发生了重复。明显使用 computed 计算属性的效率更高:

computed: {
  fullName: function() {
    return this.firstName + ' ' + this.lastName
  }
}
1
2
3
4
5
📢 上次更新: 2022/09/02, 10:18:16