再來是跟方法、事件有關的功能,可以追蹤響應式變數,或當該變數異動時可以執行相對應的運算邏輯。
computed
將一個變數宣告為computed
屬性,其效果為該變數會自動追蹤computed function 內使用到的ref 變數。當參考的ref 變數發生變化,會自動執行computed function 並讓computed
變數獲得新的值。
當宣告的變數是需要透過運算取得結果時,可以使用computed
,強調取得 "值"。
<script setup>
// 引用computed
import { ref, computed } from 'vue'
/* 省略 */
const hideCompleted = ref(false)
const todos = ref([
{ id: id++, text: 'Learn HTML', done: true },
{ id: id++, text: 'Learn JavaScript', done: true },
{ id: id++, text: 'Learn Vue', done: false }
])
const filteredTodos = computed(() => {
// 因為function 中引用`todos` 以及 `hideCompleted` 兩個 ref
// 當`todos` 以及 `hideCompleted` 有變動就會執行方法,獲得新的todo 清單
return hideCompleted.value
? todos.value.filter((t) => !t.done)
: todos.value
})
/* 省略 */
</script>
/* 省略 */
這邊值得注意的是,當直接做 todos.value.push(…)
的時候,並不會觸發computed
。原因如下:
Vue 對於響應式變數的追蹤所關注的是記憶體快取位置是否有變動,故computed
追蹤的是todos
的記憶體位置,而非todos
的值 (也就是todos.value
)。
當hideCompleted == false
,即使你對 todos.value
執行 push()
,其引用的記憶體位置不會改變。
filteredTodos
回傳的也是 todos.value
,不會重新計算;
而當hideCompleted == true
,filter()
回傳的新陣列有不同的記憶體位置,因此 Vue 判定計算函數需要重新執行。
watch
當監聽的ref 變動則觸發指定的動作,像是把onchange 事件設定在變數上面,強調"動作"。
<script>
export default {
data() {
return {
todoId: 1
detail: {
content: 'shopping',
date: '2024-01-01'
}
}
},
watch: {
todoId(newId, oldId) {
/* do something... */
}
}
}
</script>
/* 省略 */
watch
預設進行淺層監聽,意即如果你watch
的對象是 detail
的物件,當content
或date
變動時不會觸發watch function。若要監聽到底下的屬性可以利用deep 關鍵字。如以下範例,當deep=true
,修改detail.name
或觸發方法newDetail
皆可以看到log;反之,只有觸發方法newDetail
可以看到log。
<script>
export default {
data() {
return {
detail: {
name: 'test',
age1: 5
}
}
},
watch: {
detail: {
handler(newQuestion, oldQuestion) {
console.log('deep')
},
deep: true
}
},
methods: {
newDetail(){
this.detail = { name: 'ok', age1: 1}
}
}
}
</script>
method
上面的範例有一個關鍵字methods
,就是宣告屬於這個組件的function。
<script>
export default {
data() {
return {
getFromMethodValue: false,
refBoolean: false
}
},
methods: {
returnRefBoolean(){
return this.refBoolean
},
hint(){
alert('hint message')
}
}
}
</script>
<template>
<!--如果畫面上的值是呼叫method 取得,則會有響應效果-->
<p>refBoolean: {{returnRefBoolean()}}</p>
<!--點下面的p,上面的p會跟著響應-->
<p @click="refBoolean = !refBoolean">[click to change refBoolean]</p>
<!--也可以當作一般方法使用-->
<p @click="hint">show message</p>
</template>
以我的看法三種的使用時機及場景如下
References:
https://ithelp.ithome.com.tw/articles/10274622
https://zh-hk.vuejs.org/guide/essentials/watchers.html