Hi 大家好,今天我們要來看的是「模板引用」的章節。
還記得之前我們提到的 ref
嗎?
ref
除了可以用來綁定響應式的狀態,它還能被使用在 <template>
模板中,幫助我們操作 DOM 元素(招式真多)
今天會學習到的部分:
- 模板引用定義、語法
- 訪問模板引用
- 模板引用 vs. 偵聽器
- v-for 中的模板引用
- 函數模板引用
今天也會提到一點 生命週期 和 偵聽器,一起 review 熱身一下🌟
然後我們就開始吧!
ref
可以作為一個特殊的屬性,讓我們指定我們想要操作的「DOM 元素」。
例如,如果我們想與頁面上的 input
元素建立關聯,可以在 input
tag 上綁定 ref
屬性來實現。
注意:由於 DOM 元素操作是需要在掛載後才可以操作的,因此通常會搭配 onMounted()
函式來定義我們要操作的邏輯。
const 自定義變數 = ref(渲染前,元素的預設值);
// 在模板中綁定一個 DOM 元素(ref 屬性的值 = 自定義變數,需要和 <script> 定義的同名)
<綁定的元素 ref="自定義變數" />
(宣告方式以需求為準,這邊以 const
示例)
官方文件:這可能很有用,例如說在組件掛載時將焦點設置到一個 input 元素上,或在一個元素上初始化一個第三方庫。
const input = ref(null);
// 在模板中綁定 input 元素(ref 屬性的值 = input,和 <script> 定義的同名)
<input ref="input" />
來看看掛載完成後,如何使用它吧!
實際情境可能會是:
我們想要在組件掛載後,對頁面上的
input
元素進行操作。而在 script setup 定義的變數、函式,是在創建階段被創造實例的,而對於 DOM 的操作必須在「組件掛載完成後」進行,這時候就需要 cue 到 onMounted()!
因此我們可以這麼做:
- 於 script setup 定義 ref 響應式狀態,初始化 DOM 元素。
- 使用 onMounted() 定義掛載後要更新這個 DOM 元素的操作邏輯。
- 將在 script setup 中定義的響應式變數,和 template 中 DOM 元素上的 ref 屬性綁定。
<script setup>
import { onMounted, ref } from "vue";
const input = ref(null);
onMounted(() => {
input.value.value = "我是預設文字";
});
</script>
<template>
<input ref="input" />
</template>
以上我們做了什麼:
<script setup>
中定義:const input = ref(null);
:設置初始值為 null
,並綁定一個變數 input
。input
變數就是在模板中要操作的 ref
屬性的值。null
就可以~)
onMounted()
函式,於掛載完成後,將 input
元素的值設置為 我是預設文字
。若我們於 onBeforeMount()
中操作:
就會報錯~(有懂生命週期的重要性了嗎!)
偵聽模板引用時,需要注意:在組件掛載完成之前,模板中的元素尚未生成,因此該 DOM 元素的值會是 null
。
而我們可以使用「判斷式」來確認它是否存在。
watchEffect(() => {
if (input.value) {
// 掛載完成,元素存在時
input.value.value = "我是預設文字";
} else {
// 掛載前、或卸載完成時
}
})
需要 v3.2.25 及以上版本
當在 v-for 中使用模板引用時,對應的 ref 中包含的值是一個數組,它將在元素被掛載後包含對應整個列表的所有元素
我們可為其宣告一個掛載前的值 []
,綁定到 ref
屬性上,再搭配 v-for
的語法使用。
可以這麼做:
<script setup>
import { onMounted, ref } from "vue";
const list = ref(["a", "b", "c"]);
const itemRefs = ref([]);
onMounted(() => {
console.log(list.value);
});
</script>
<template>
<li v-for="item in list" ref="itemRefs">{{ item }}</li>
</template>
在掛載階段,v-for
將渲染出 list
中響應式狀態的陣列元素,而掛載後,印出 list.value
:
官方文件:應該注意的是,ref 數組並不保證與源數組相同的順序。
由於 ref
屬性綁定的是 itemRefs
,這個陣列是在完成掛載、渲染後生成的,因此它根據的是:DOM 元素的實際渲染順序,不一定會與 list
陣列元素的原始順序一致。
模板引用除了一般的變數形式,也可以使用「函式」作為參數,而我們需要使用動態綁定 :ref
。
<綁定的元素 :ref="自定義的函式" />
null
)。我們來看看實際例子:
<template>
<input
:ref="(el) => { if (el) { el.value = '我是預設文字'; } }"/>
</template>
input
元素上使用動態綁定::ref
綁定了 (el) => { if (el) { el.value = '我是預設文字'; } }
這個函式,而 el
代表渲染完成的 DOM 元素,因此在函式中,可以直接對 el
執行渲染完成後的邏輯。el.value = '我是預設文字';
。備註:每次更新都會被觸發,當元素卸載也會再觸發一次。
我們來加點邏輯,看看它卸載後的觸發!
// referenceChild.vue
<template>
<input
:ref="
(el) => {
if (el) {
console.log('元素掛載:', el); // 元素掛載時
el.value = '我是預設文字';
} else {
console.log('元素卸載:', el); // 元素卸載時,el 為 null
}
}"/>
</template>
然後我們使用一個父組件控制它的呈現:
<script setup>
import ReferenceChild from "./referenceChild.vue";
import { ref } from "vue";
const show = ref(true);
const change = function () {
show.value = !show.value;
};
</script>
<template>
<ReferenceChild v-if="show" />
<button @click="change">切換卸載</button>
</template>
我們看看瀏覽器上的效果:
子元素被卸載後,確實也觸發了在 :rel
中定義的邏輯判斷 console.log('元素卸載:', el)
。
這一小節假設你已了解組件的相關知識,或者你也可以先跳過這裡,之後再回來看。
跳級生先看~我稍後補(噓)
直接用屬性定義在掛載後要對 DOM 元素做的操作還蠻酷的(小腦袋有滿足到 🎼🎼🎼)而明天~我們要來補齊 Vue 一直在提到的 組件基礎 囉~~
https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day26