【Vue】03 - 監聽、響應事件:computed、watch、method

  • 51
  • 0
  • Vue
  • 2024-12-27

再來是跟方法、事件有關的功能,可以追蹤響應式變數,或當該變數異動時可以執行相對應的運算邏輯。

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 == truefilter() 回傳的新陣列有不同的記憶體位置,因此 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