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.reversedMsg
的getter
函數。我們在Chrome瀏覽器控制檯,直接修改vm.msg
。vm.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
中可以分爲getter
和setter
。默認情況下computed
是沒有setter
的,computed
只是預設了getter
,也就是隻能讀取,不可以改變設值。
在vue
中當需要賦值給計算屬性的時候,將調用setter
函數。多用於在模板組件中需要修改計算屬性自身的值的時候。只有當計算屬性中的屬性被直接賦值的時候,纔會走setter
函數。注意:setter
和getter
是相互獨立的。
<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>