計(jì)算屬性computed和偵聽器watch
一萨螺、計(jì)算屬性computed
計(jì)算屬性,顧名思義愧驱,就是計(jì)算出一個屬性慰技,并且計(jì)算屬性的求值結(jié)果會被緩存起來,只在它的響應(yīng)式依賴發(fā)生改變時該屬性才會重新求值组砚。
計(jì)算屬性一般用于簡化模板中的表達(dá)式吻商,如下,只要 firstName
和lastName
還沒有發(fā)生改變糟红,多次訪問 fullName
計(jì)算屬性會立即返回之前的計(jì)算結(jié)果艾帐,而不必再次執(zhí)行函數(shù)。
<div id="app">
<!--這種方式 若出現(xiàn)次數(shù)多盆偿,或內(nèi)容冗長柒爸,則很繁瑣 -->
<p>{{ firstName + lastName }}</p>
<!--使用計(jì)算屬性簡化模板表達(dá)式 -->
<p>{{ fullName }}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
firstName: "梅梅",
lastName: "李",
},
computed: {
fullName: function () {
return this.firstName + this.lastName
}
}
})
</script>
組件模板應(yīng)該只包含簡單的表達(dá)式,復(fù)雜的表達(dá)式則應(yīng)該重構(gòu)為計(jì)算屬性或方法事扭。復(fù)雜的表達(dá)式會讓模板變得不是那么聲明式捎稚。我們應(yīng)該盡量描述理應(yīng)出現(xiàn)什么,而非如何計(jì)算那個值求橄。而且計(jì)算屬性和方法使得代碼可以重用今野。
此外應(yīng)該把復(fù)雜的計(jì)算屬性分割為極可能多簡單的屬性。
computed:{
basePrice(){
return this.manufactureCost / ( 1 - this.profitMargin)
},
discount(){
return this.basePrice * (this.discountPercent || 0)
},
finalPrice(){
return this.basePrice - this.discount
}
}
也可以進(jìn)行一些更復(fù)雜的操作:
<div id="app">
<h2>總價格:{{ totalPrice }}</h2>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
// 給一個對象數(shù)組book,數(shù)組每一個元素都是一個對象
books: [
{ id: 110, name: "編程之美", price: 119 },
{ id: 111, name: "代碼大全", price: 115 },
{ id: 112, name: "深入理解計(jì)算機(jī)原理", price: 99 },
{ id: 113, name: "圖解HTTP", price: 85 },
]
},
computed: {
totalPrice: function () {
let result = 0
for (let i = 0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
</script>
computed的完整形式,其中包括一個setter方法和一個getter方法罐农。一般只需要實(shí)現(xiàn)getter方法腥泥。setter一般是空的,不希望別人給這個計(jì)算屬性設(shè)置值啃匿,就會直接刪去setter方法。如:
<script>
var app = new Vue({
el: '#app',
data: {
firstName: '旺旺',
lastName: '仙貝'
},
computed: {
fullName: {
// 未給fullName外加賦值時,輸出為get方法的輸出
// 但如果外界再賦值溯乒,則會輸出 console.log('---', newValue)
set: function (newValue) {
console.log('---', newValue)
},
get: function () {
return 'abc'
// 之后使用fullName屬性時就會調(diào)用get方法夹厌,返回abc
}
}
}
})
</script>
二、偵聽屬性watch
偵聽屬性watch可以監(jiān)聽data中指定數(shù)據(jù)的變化裆悄,然后觸發(fā)這個watch中對應(yīng)的function處理函數(shù)矛纹。當(dāng)我們需要深度監(jiān)聽對象中的屬性時,可以打開deep:true
選項(xiàng), 這樣便會對對象中的每一項(xiàng)屬性進(jìn)行監(jiān)聽光稼。
通過watch除了可以監(jiān)聽一些DOM元素外或南,還可以監(jiān)聽DOM之外的元素,比如路由對象艾君。
watch:{
'$route': function ( newVal, oldVal ){
console.log(`之前的路由:${oldVal},現(xiàn)在的路由${newVal}`);
if (newVal.path === '/register'){
console.log('這是注冊組件')采够;
}else{
console.log('這是登錄組件')
}
}
}
當(dāng)需要在數(shù)據(jù)變化時執(zhí)行異步或開銷較大的操作時,watch是最有用的冰垄。使用 watch
選項(xiàng)允許我們執(zhí)行異步操作 (訪問一個 API)蹬癌,限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前虹茶,設(shè)置中間狀態(tài)逝薪。這些都是計(jì)算屬性無法做到的。
以下是官網(wǎng)例子:
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因?yàn)?AJAX 庫和通用工具的生態(tài)已經(jīng)相當(dāng)豐富蝴罪,Vue 核心代碼沒有重復(fù) -->
<!-- 提供這些功能以保持精簡董济。這也可以讓你自由選擇自己更熟悉的工具。 -->
<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` 發(fā)生改變要门,這個函數(shù)就會運(yùn)行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一個通過 Lodash 限制操作頻率的函數(shù)虏肾。
// 在這個例子中,我們希望限制訪問 yesno.wtf/api 的頻率
// AJAX 請求直到用戶輸入完畢才會發(fā)出暂衡。想要了解更多關(guān)于
// `_.debounce` 函數(shù) (及其近親 `_.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>
三、computed狂巢、watch撑毛、methods的對比
computed
- computed形式上是function()函數(shù),主要當(dāng)做屬性來使用唧领;監(jiān)聽data里的數(shù)據(jù)變化藻雌,會根據(jù)data數(shù)據(jù)變化而自動重新計(jì)算;
- computed中屬性的結(jié)果會被緩存斩个,除非依賴的響應(yīng)式屬性變化才會重新計(jì)算胯杭;
- 最后一定要有個返回值,而且不帶參數(shù)受啥。
watch
- 監(jiān)聽一個對象做个,鍵是需要觀察的表達(dá)式鸽心,值是對應(yīng)回調(diào)函數(shù)。
- 主要用來監(jiān)聽某些特定數(shù)據(jù)的變化居暖,從而進(jìn)行某些具體的業(yè)務(wù)邏輯顽频;可以看作是computed和methods的結(jié)合體。
methods
- 方法表示一個具體的操作太闺,主要書寫業(yè)務(wù)邏輯糯景;methods的返回值和參數(shù)都是可有可無的。
- methods無法監(jiān)聽data數(shù)據(jù)省骂,并且methods中的方法誒有緩存蟀淮,每次刷新都會去執(zhí)行。
總結(jié):
如果一個值依賴多個屬性(多對一)钞澳,用computed
更加方便怠惶;
如果一個值變化后會引起一系列操作,或一個值變化會引起一系列值的變化(一對多)略贮,用watch
更方便一些甚疟。
watch的回調(diào)里面會傳入監(jiān)聽屬性的新舊值,通過這兩個值可以做一些特定的操作逃延;computed通常就是簡單的計(jì)算览妖。