---
tags: Javascript, Vue
---
# Vue watch和computed筆記
## watch
1. 監聽"單一"變數觸發事件
1. 該函式可同時操作多個變數操作
### 監聽單一元素
監聽當`text`改變,觸發函式,`watch`的`callback`函式會有新值跟舊值傳入
```javascript=
new Vue({
// ...
data: {
// ...
text: '',
},
watch: {
// ...
text(new, old) {
console.log(`文字改變,從${old}變成${new}`);
}
}
});
```
### Deep Watchers深度觀察
當要監聽一個物件的時候可以使用此方法,`newValue`以及`oldValue`會返回一個物件
```javascript=
new Vue({
// ...
data: {
// ...
product: {
'name': '電腦',
'price': 100
},
},
watch: {
product:{
handler(newValue, oldValue) {
console.log(`更改後${newValue},更改前${oldValue}`);
// Note: `newValue` will be equal to `oldValue` here
// on nested mutations as long as the object itself
// hasn't been replaced.
},
deep: true
}
}
});
```
### 強制創建`watch`實例
可以使用`$watch`創建觀察者
觀察一個屬性名稱:
```javascript=
this.$watch('a', (newVal, oldVal) => {})
```
使用$watch()實例方法強制創建觀察者:
```javascript=
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
```
## computed
1. 監聽多個變數觸發事件
1. 會產生一個值
如果有需要複雜計算的屬性,會建議放在`computed`裡面,`computed`預設是`getter-only`,就是只能取得值但不能做修改,來看以下範例
原先我們要在模板內使用以下程式碼做運算,但如果過多邏輯在模板內,會變得難維護
```vue=
<p>{{ `是否擁有商品: ${this.author.products.length > 0 ? 'Yes' : 'No'}` }}</p>
export default {
data() {
return {
author: {
products: [
'電腦',
'滑鼠',
'鍵盤'
]
}
}
}
}
```
我們可以在`computed`加上`publishedproductssMessage`,然後改變模板寫法,以下結果就跟上述範例是一樣的。
```vue=
<p>{{ `是否擁有商品: ${ publishedproductssMessage }` }}</p>
export default {
data() {
return {
author: {
products: [
'電腦',
'滑鼠',
'鍵盤'
]
}
}
},
computed: {
// a computed getter
publishedproductssMessage() {
return this.author.products.length > 0 ? 'Yes' : 'No'
}
}
}
```
`computed`函式內的值有改變,才會更動,如果沒有更動他就跟`methods`一樣,比如取得時間。
```vue=
computed: {
getTime() {
return new Date().toLocaleTimeString();
},
}
```
預設情況下`computed`是不能寫入值,可以透過`getter` 和 `setter`來把值寫回`data`,查看範例。
當`fullName`裡面的資料被更新時,才會觸發`fullName`的`getter`,順序為`getter->updated`,當我們要進行設值時,就將程式碼寫在`setter`中,點擊按鈕設值,執行順序為`setter->getter->updated`
,但要注意`setter`不一定會觸發`getter`除非有更改到`getter`裡面的值。
![](https://i.imgur.com/kmCtluE.gif)
```vue=
<div>
<p>firstName: {{ firstName }}</p>
<p>lastName: {{ lastName }}</p>
<p>fullName: {{ fullName }}</p>
<input type="text" v-model="inputName" />
<button @click="fullName=inputName">更新</button>
</div>
export default {
data() {
return {
firstName: "Joe",
lastName: "Wang",
inputName: "",
};
computed: {
fullName: {
// getter
get() {
return this.firstName + " " + this.lastName;
},
// setter
set(newValue) {
[this.firstName, this.lastName] = newValue.split(" ");
},
},
},
}
```