And the listener properties calculation
Computed Property
The expression in the template is very convenient, but They are primarily designed for simple operation. Putting too much logic in the template template will be too heavy and difficult to maintain. E.g:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
In this place, the template is no longer a simple declarative logic. You have to look at some time to realize that here is you want to display variable message
flip string. When you want to refer to flip the string here many times in the template, it will be more difficult to handle.
So, for any complex logic, you should use the calculation attribute .
Examples basis
<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: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
result
Original message: "Hello"
Computed reversed message: "olleH"
Here we declare a calculated property reversedMessage
. We offer as a function of the property vm.reversedMessage
getter function:
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
You can open the browser console modified example of the vm itself.
vm.reversedMessage
The value is always dependent on vm.message
the value.
You can be as binding as common property of binding to calculate properties in the template. Vue know vm.reversedMessage
rely on vm.message
, so when vm.message
change occurs, all dependent vm.reversedMessage
binding will be updated. And best of all is that we have to declaratively create this dependency: calculate the property getter functions are no side effects (side effect), making it easier to test and understand.
Calculation method vs property cache
You may have noticed that we can achieve the same effect by calling in an expression method:
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
We can define the same function as a method rather than a calculated property. The final results of the two methods is indeed identical. However, the difference is calculated based on their properties are dependent responsive caching . They will only re-evaluated at the time-dependent change of Formula correlation response. This means that as long as message
no change, many visits to reversedMessage
the calculation results before the property will return immediately to calculate, without having to perform functions again.
This also means that the following calculated property will not be renewed, because Date.now()
not dependent response of formula:
computed: {
now: function () {
return Date.now()
}
}
In contrast, whenever the trigger re-rendering, calling the method will always execute the function once again.
Why do we need to cache? Suppose we have a performance overhead is relatively large computational properties of A , it needs to traverse a huge array and do a lot of calculations. Then we may have other properties depend on the calculation A . If there is no cache, we will inevitably multiple executions A getter is! If you do not want to have the cache, instead of using the method.
Computed Property vs listeners property
Vue provides a more versatile way to observe changes and the response data on the Vue instance: listener properties . When you have some data with other data needs to change and change, you can easily abused watch
- especially if you previously used AngularJS. Often, however, a better practice is to use the calculation attribute rather than a command-style watch
callback. Come to think of this example:
<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
}
}
})
The above code is the command type and repetitive. It was compared with the calculated properties version:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
setter calculated properties
The default attribute is calculated only getter, but if necessary you can also provide a setter:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
Now run vm.fullName = 'John Doe'
time, setter will be called, vm.firstName
and vm.lastName
will be updated accordingly.
Listener
Although the computing properties more appropriate in most cases, but sometimes requires a custom listener. That's why Vue by watch
providing a more general approach options to respond to changes in the data. When the need to perform asynchronous data change operation or large overhead, this approach is most useful.
E.g:
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/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 () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
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>
In this example, use the watch
option allows us to perform asynchronous operations (the API to access a), we perform the operation frequency limit and before we get the final result, an intermediate state. These are computed attribute can not be done.
In addition watch
to the options, you can also use the command-style vm. $ Watch API .