一些初學者可能對計算屬性和偵聽屬性的使用場景感到困惑不解,本文主要介紹二者的用法、使用場景及其二者的區別。 本文的代碼請猛戳github博客,紙上得來終覺淺,你們動手多敲敲代碼!html
計算屬性是自動監聽依賴值的變化,從而動態返回內容,監聽是一個過程,在監聽的值變化時,能夠觸發一個回調,並作一些事情。它有如下幾個特色:前端
計算屬性由兩部分組成:get和set,分別用來獲取計算屬性和設置計算屬性。默認只有get,若是須要set,要本身添加。另外set設置屬性,並非直接修改計算屬性,而是修改它的依賴。vue
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
//this.fullName = newValue 這種寫法會報錯
var names = newValue.split(' ')
this.firstName = names[0]//對它的依賴進行賦值
this.lastName = names[names.length - 1]
}
}
}
複製代碼
如今再運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相應地被更新。git
能夠像綁定普通屬性同樣在模板中綁定計算屬性,在定義上有區別:計算屬性的屬性值必須是一個函數。github
data:{ //普通屬性
msg:'浪裏行舟',
},
computed:{ //計算屬性
msg2:function(){ //該函數必須有返回值,用來獲取屬性,稱爲get函數
return '浪裏行舟';
},
reverseMsg:function(){
//能夠包含邏輯處理操做,同時reverseMsg依賴於msg,一旦msg發生變化,reverseMsg也會跟着變化
return this.msg.split(' ').reverse().join(' ');
}
}
複製代碼
二者最主要的區別:computed 是能夠緩存的,methods 不能緩存;**只要相關依賴沒有改變,屢次訪問計算屬性獲得的值是以前緩存的計算結果,不會屢次執行。**網上有種說法就是方法能夠傳參,而計算屬性不能,其實並不許確,計算屬性能夠經過閉包來實現傳參:面試
:data="closure(item, itemName, blablaParams)"
computed: {
closure () {
return function (a, b, c) {
/** do something */
return data
}
}
}
複製代碼
Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變更:偵聽屬性watch。watch中能夠執行任何邏輯,如函數節流,Ajax異步獲取數據,甚至操做 DOM(不建議)。segmentfault
<template>
<div class="attr">
<h1>watch屬性</h1>
<h2>{{ $data }}</h2>
<button @click="() => (a += 1)">修改a的值</button>
</div>
</template>
<script>
export default {
data() {
return {
a: 1,
b: { c: 2, d: 3 },
e: {
f: {
g: 4
}
},
h: []
};
},
watch: {
a: function(val, oldVal) {
this.b.c += 1;
},
"b.c": function(val, oldVal) {
this.b.d += 1;
},
"b.d": function(val, oldVal) {
this.e.f.g += 1;
},
e: {
handler: function(val, oldVal) {
this.h.push("浪裏行舟");
},
deep: true //用於監聽e對象內部值的變化
}
}
};
</script>
複製代碼
使用 watch 來監聽數據變化的時候除了經常使用到 handler 回調,其實其還有兩個參數,即是:緩存
<template>
<button @click="obj.a = 2">修改</button>
</template>
<script>
export default {
data() {
return {
obj: {
a: 1,
}
}
},
watch: {
obj: {
handler: function(newVal, oldVal) {
console.log(newVal);
},
deep: true,
immediate: true
}
}
}
</script>
複製代碼
以上代碼咱們修改了 obj 對象中 a 屬性的值,咱們能夠觸發其 watch 中的 handler 回調輸出新的對象,而若是不加 deep: true,咱們只能監聽 obj 的改變,並不會觸發回調。同時咱們也添加了 immediate: true 配置,其會當即以 obj 的當前值觸發回調。 咱們再看一個實際工做中常遇到的場景:組件建立的時候咱們獲取一次列表的數據,同時監聽input框,每當發生變化的時候從新獲取一次篩選後的列表。bash
created(){
this.fetchPostList()
},
watch: {
searchInputValue(){
this.fetchPostList()
}
}
複製代碼
有沒有辦法優化一下呢?服務器
watch: {
searchInputValue:{
handler: 'fetchPostList',
immediate: true
}
}
複製代碼
首先,在watchers中,能夠直接使用函數的字面量名稱;其次,聲明immediate:true表示建立組件時立馬執行一次。
從上面流程圖中,咱們能夠看出它們之間的區別:
除此以外,有點很重要的區別是:計算屬性不能執行異步任務,計算屬性必須同步執行。也就是說計算屬性不能向服務器請求或者執行異步任務。若是遇到異步任務,就交給偵聽屬性。watch也能夠檢測computed屬性。
接下去咱們看個用watch來實現防抖的例子:直到用戶中止輸入超過1秒後,才更新視圖。
<template>
<div>
{{ fullName }}
<div>firstName: <input v-model="firstName" /></div>
<div>lastName: <input v-model="lastName" /></div>
</div>
</template>
<script>
import { setTimeout } from "timers";
export default {
data: function() {
return {
firstName: "浪裏行舟",
lastName: "前端工匠",
fullName: "浪裏行舟 前端工匠"
};
},
watch: {
firstName: function(val) {
clearTimeout(this.firstTimeout);
this.firstTimeOut = setTimeout(() => {
this.fullName = val + " " + this.lastName;
}, 1000);
},
lastName: function(val) {
clearTimeout(this.lastTimeout);
this.lastTimeOut = setTimeout(() => {
this.fullName = this.firstName + " " + val;
}, 1000);
}
}
};
複製代碼
計算屬性適合用在模板渲染中,某個值是依賴了其它的響應式對象甚至是計算屬性計算而來;而偵聽屬性適用於觀測某個值的變化去完成一段複雜的業務邏輯。
歡迎關注公衆號:前端工匠,你的成長咱們一塊兒見證!