计算属性和观察者

计算属性

模板内嵌表达式虽然方便,但仅适合简单运算。逻辑复杂表达式不易维护,比如:

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

对于复杂逻辑,弊端有二:不易弄懂其逻辑;不便多次复用。

对于任何复杂逻辑,你应该使用计算属性(computed property)。

简单例子

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    reversedMessage: function() {
      return this.message.split('').reverse().join('')
    }
  }
})

计算属性 vs 方法

从最终结果上看,计算属性和方法完全相同。唯一区别在于,计算属性是缓存的。只要它依赖的属性不变,多次调用计算属性,不会重新计算。

这意味着如下例子中的计算属性不会更新,因为 Date.now() 不是响应式依赖:

computed: {
  now: function() {
    return Date.now()
  }
}

计算属性 vs 被观察属性

Vue 确实提供了一个更通用的方法来观察 Vue 实例的数值,并对其变化作相应:观察属性(watch properties)。观察属性容易被滥用,尤其 Angular 人士。然而,通常使用计算属性更佳。比如:

<div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  }, 

  watch: {
    firstName: function(val) {
      this.fullName = val + ' ' + this.lastName
    },

    lastName: function(val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

以上代码是命令式且重复,与计算属性版本做比较:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function() {
      return this.firstName + ' ' + this.lastName
    }
  }
})

可以看到,计算属性更简单。

计算 Setter

计算模型默认只读,若要需要,可以设置其可写:

computed: {
  fullName: {
    get: function() {
      return this.fullName + ' ' + this.lastName
    },

    set: function(newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

现在,当你执行 vm.fullName = 'John Doe' 时,会唤起 setter ,并且会自动更新 vm.firstNamevm.lastName

观察者

计算属性可满足大多数场景,但有时自定义的观察者函数也是必须的。这也是 Vue 提供通用响应选项 watch 的原因。一般适合处理异步回调或计算量复杂的操作。

比如:

<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>

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    question: function(newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.getAnswer()
    }
  },

  methods: {
    getAnswer: _.debounce(
      function () {
        if (this.question.indexOf('?') === -1) {
          this.answer = 'Questions usually contain a question mask. ;-)'
          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
          })
      },
      500
    )
  }
})

除了使用 watch 选项,也可以使用命令式的 vm.$watch API。

REF

results matching ""

    No results matching ""