2024-09-21|閱讀時間 ‧ 約 22 分鐘

EP13 - 模板參照

Template Refs 模板參照是什麼東西啊?
我倒是很需要模板!希望可以重複使用啊~
不知道是不是這個東西?

雖然 Vue 的聲明式渲染模型為您抽象了大部分的直接 DOM 操作,但仍然可能有需要直接訪問底層 DOM 元素的情況。為了實現這一點,我們可以使用特殊的 ref 屬性:

<template>
<input ref="input">
</template>

ref 是一個特殊屬性,類似於在 v-for 章節中討論的 key 屬性。它允許我們在元素或子組件實例被掛載後獲得對特定 DOM 元素或子組件實例的直接參照。例如,在您需要在組件掛載時程序化地聚焦輸入框,或在元素上初始化第三方庫時非常有用。

訪問模板參照 - Accessing the Refs​

使用 Composition API 獲取參照時,我們可以使用 useTemplateRef() 3.5+助手:

<script setup>
import { useTemplateRef, onMounted } from 'vue'

// 第一個參數必須與模板中的 ref 值匹配
const input = useTemplateRef('my-input')

onMounted(() => {
input.value.focus()
})
</script>

<template>
<input ref="my-input" />
</template>

使用 TypeScript 時,Vue 的 IDE 支援和 vue-tsc 會根據 ref 屬性使用的元素或組件,自動推斷 inputRef.value 的類型。

3.5 版本之前的用法

在 3.5 版本之前,useTemplateRef() 尚未引入,我們需要宣告一個名稱與模板 ref 屬性值匹配的 ref

<script setup>
import { ref, onMounted } from 'vue'

// 宣告一個 ref 來保存元素參照
// 名稱必須與模板 ref 值匹配
const input = ref(null)

onMounted(() => {
input.value.focus()
})
</script>

<template>
<input ref="input" />
</template>

如果不使用 <script setup>,請確保在 setup() 中返回 ref

export default {
setup() {
const input = ref(null)
// ...
return {
input
}
}
}

請注意,您只能在組件掛載後訪問參照。如果您嘗試在模板表達式中訪問 input,它在第一次渲染時會是 null。這是因為元素只有在第一次渲染後才存在!

如果您嘗試監視模板參照的變化,請確保考慮到參照值為 null 的情況:

watchEffect(() => {
if (input.value) {
input.value.focus()
} else {
// 還未掛載,或者元素被卸載(例如通過 v-if)
}
})

另請參見:模板參照的類型定义

v-for 中的參照 - Refs inside v-for​

需要 v3.2.25 或更高版本

ref 用於 v-for 時,對應的 ref 應該包含一個數組值,該數組在掛載後將填充元素:

<script setup>
import { ref, useTemplateRef, onMounted } from 'vue'

const list = ref([
/* ... */
])

const itemRefs = useTemplateRef('items')

onMounted(() => console.log(itemRefs.value))
</script>

<template>
<ul>
<li v-for="item in list" ref="items">
{{ item }}
</li>
</ul>
</template>

在 3.5 版本之前的使用情況

<script setup>
import { ref, onMounted } from 'vue'

const list = ref([
/* ... */
])

const itemRefs = ref([])

onMounted(() => console.log(itemRefs.value))
</script>

<template>
<ul>
<li v-for="item in list" ref="itemRefs">
{{ item }}
</li>
</ul>
</template>

需要注意的是,ref 數組並不保證與源數組具有相同的順序。

函數參照 - Function Refs​

除了使用字串鍵,ref 屬性也可以綁定到一個函數,該函數會在每次組件更新時被調用,並允許您完全靈活地選擇將元素引用存儲在何處。該函數會接收元素引用作為第一個參數:

<template>
<input :ref="(el) => { /* 將 el 指派給某個屬性或 ref */ }">
</template>

注意,我們使用了一個動態的 :ref 綁定,因此可以傳遞一個函數而不是 ref 名稱字串。當元素卸載時,參數將為 null。當然,您也可以使用一個方法來代替內聯函數。

在組件上使用參照 - Ref on Component​

這部分假設您已經具備組件的相關知識。如果沒有,可以跳過,稍後再回來閱讀。

ref 也可以用在子組件上。在這種情況下,ref 將引用子組件實例:

<script setup>
import { useTemplateRef, onMounted } from 'vue'
import Child from './Child.vue'

const childRef = useTemplateRef('child')

onMounted(() => {
// childRef.value 將持有 <Child /> 的實例
})
</script>

<template>
<Child ref="child" />
</template>

3.5 之前的用法:

<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

const child = ref(null)

onMounted(() => {
// child.value 將持有 <Child /> 的實例
})
</script>

<template>
<Child ref="child" />
</template>

如果子組件使用 Options API 或沒有使用 <script setup>,那麼引用的實例將與子組件的 this 相同,這意味著父組件可以完全訪問子組件的每個屬性和方法。這使得在父子組件之間創建緊密耦合的實現細節變得容易,因此應僅在絕對需要時使用組件 ref。在大多數情況下,您應該首先嘗試使用標準的 propsemit 接口來實現父子交互。

這裡有一個例外:使用 <script setup> 的組件默認是私有的:父組件引用使用 <script setup> 的子組件時,無法訪問任何內容,除非子組件選擇使用 defineExpose 宏來暴露公共接口:

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

// 編譯器宏(如 defineExpose)不需要被導入
defineExpose({
a,
b
})
</script>

當父組件通過模板 ref 獲得此組件的實例時,取回的實例將是 { a: number, b: number } 的形狀(ref 將自動解包,就像在正常實例上一樣)。

另見:組件模板 Refs 的類型化

Q:總結一下tempelate跟ref關係?

<template>ref 在 Vue 中有著密切的關係,因為 ref 通常是在模板中使用來獲取對 DOM 元素或子組件實例的引用。這兩者的關係可以總結如下:

templateref 的關係

1. 定義模板結構

  • <template> 標籤用來定義 Vue 組件的 HTML 結構,這是組件的視圖部分。
  • 在模板內部,你可以使用標準的 HTML 標籤以及 Vue 的指令來構建組件的界面。

2. 引用 DOM 元素

  • ref 是一個特殊屬性,當應用於模板中的 DOM 元素時,Vue 會在組件掛載後將該元素的引用存儲到相應的變量中。
  • 例如,<input ref="inputElement"> 會讓你在組件邏輯中使用 this.$refs.inputElement(或在 Composition API 中使用 ref 變量)來訪問該輸入框元素。

3. 引用子組件

  • ref 也可以用於子組件,允許你在父組件中直接訪問子組件實例及其方法和屬性。
  • 例如,<ChildComponent ref="childComponent"> 會讓你在父組件中使用 this.$refs.childComponent 來訪問子組件的實例。

示例代碼

以下是一個簡單的示例,展示了如何在模板中使用 ref 來引用 DOM 元素和子組件:

<template>
<div>
<!-- 引用 DOM 元素 -->
<input ref="inputElement" placeholder="Type something" />
<!-- 引用子組件 -->
<ChildComponent ref="childComponent" />
</div>
</template>

<script>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'

export default {
components: { ChildComponent },
setup() {
// 使用 ref 來保存 DOM 元素的引用
const inputElement = ref(null)
// 使用 ref 來保存子組件實例的引用
const childComponent = ref(null)

onMounted(() => {
// 可以在組件掛載後訪問這些引用
console.log(inputElement.value) // DOM 元素
console.log(childComponent.value) // 子組件實例
})

return {
inputElement,
childComponent
}
}
}
</script>
  • <template>:用於定義組件的視圖結構,包括 HTML 和 Vue 指令。
  • ref:用於獲取模板中 DOM 元素或子組件實例引用,從而在組件邏輯中進行操作。

透過在模板中使用 ref 屬性,你可以在 Vue 組件中輕鬆地訪問和操作具體的 DOM 元素或子組件,實現更靈活的交互和控制。

不知道是不是週末的關係?這邊怎麼看的霧濛濛www
太想放假了!各位週末愉快~
希望下次再來看這些文件會更熟一點www
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.