Template Ref 操作DOM的方法

在原生的 JavaScript 中要取得 DOM 元素需要類似這樣的語法,以取得 id 為 div1 的 DOM 元素:

var div1 = document.getElementById('div1');

如果是在 VUE,要在 Composition API 的語意環境中取得 DOM 元素,則必須在 DOM 元素放一個 ref=”xxx” 來取代 id,並宣告一個與 xxx 同名的 ref,指向那個 DOM 元素,以進行進一步的操作:

要注意的是:template ref (模板引用)在 mounted 之前為 null,要在 mounted 之後才能取得 template ref(模板引用) 的值,這是因為 DOM 元素在 Mounted 之後才會掛載在網頁上。

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

// 宣告一個 ref 來存放該元素的引用
// 必須和 <template> 的元素同名
const input = ref(null)

console.log('before Mounted',input.value)
// null
onMounted(() => {
console.log('after Mounted',input.value)
  input.value.focus()
  // <input>
})
</script>

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

v-for 跟 ref 的關係

如果想要取得 v-for 的 DOM 元素,它所對應的 ref 值會是一個陣列,陣列裡會有 v-for 渲染出來的所有 DOM 元素。

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

const list = ref([1, 2, 3])

const itemRefs = ref([])

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

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

如下圖所見,console 出來的結果是一個陣列中放著 3 個 li。

ref 在元件上使用

App.vue

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

const child = ref(null)

onMounted(() => {
  // child.value will hold an instance of <Child />
  console.log(child)
})
</script>

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

Child.vue

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

const a = 1
const b = ref(2)

// Compiler macros, such as defineExpose, don't need to be imported
defineExpose({
  a,
  b
})
</script>

當我們在父元件置入子元件時,放入 ref=”child”。

<Child ref="child" />

並且建立一個 child 常數,賦予它一個 null 的 ref,就可以透過 ref 取得以物件型態表現的子元件。

const child = ref(null)

比較特別的是在 setup function中,要多寫 defineExpose({}),子元件內部的資料才能讓父元件取得。

defineExpose({
  a,
  b
})

如下圖,在 mounted 時 console.log(child),可以看到 child 子元件內部所擁有的資料。

最後要注意的是:如果要讓父元件能夠響應式地取得子元件內部資料的變化,還是要透過 props 和 emits。

參考資料:

Leave a Reply

Your email address will not be published. Required fields are marked *