淺析setup如何通過ref獲取子組件實例中的DOM結構/數據/方法及獲取子組件實例數據都是空的處理(defineExpose API 的使用)、Vue3模板引用refs、在組合式API中使用template refs、for循環中如何獲取及重置refs、如何監聽模板引用


一、通過 ref 獲取子組件實例中的DOM結構數據及方法

  setup 怎么獲取子組件的 ref ?在 Vue3 中,如果要在父組件拿到子組件(子組件的DOM結構、數據、方法),可以通過 ref。即在父組件中定義響應式數據 ref(null) ,並綁定給子組件,在需要的時候,通過定義的響應式變量即可獲取。獲取后,即獲取了子組件的一切,可以看到子組件的DOM結構,也可以看到子組件中對外暴露的的數據和方法,並且可以直接調用。

<ExpertFormVue ref="ExpertRef"></ExpertFormVue>
const ExpertRef = ref() // 通過 ref 綁定子組件
function getSonComponent () { // 通過 ref 獲取子組件 // 獲取子組件的數據
 console.log(ExpertRef.value) console.log(ExpertRef.value.msg) }

  這里面涉及 2 個問題:

1、如何通過 ref 獲取子組件實例

  ref 用法1:響應式數據。ref 用法2:模板ref,獲取dom元素節點(重點

1const a = refnull); 2、在template中定義ref <div ref='a'>*********</div>
3、setup中獲取對應節點【在onMounted里】; 4、將a return出去;

  但是這時候你可能會發現,你無法獲取這個節點,這是什么原因呢?其實還是生命周期的問題,結合官方文檔可知:原來的created沒有了,setup充當了原來的created。

  所以在setup的時候,dom元素還沒有被創建,一切都處於混沌狀態,只有setup完畢了HTML才能完整構建,才能真正訪問到value值,所以自然無法獲取到dom節點,要想解決這個問題,就要配合鈎子函數 onMounted ,在dom掛載完畢后再進行獲取

2、為什么獲取子組件實例中的數據都是空?  ——  defineExpose API 的使用

  問題:開始的時候,我像上面寫的,怎么都拿不到子組件實例的數據和方法等。

  原因:其實寫法是對的,只不過拿到的引用是空的。子組件需要明確使用 expose 方法暴露出接口之后,才能在父組件獲取到接口引用。未暴露接口的情況下,引用的始終是一個空對象。

// 子組件導出方法,才能在父組件拿到子組件的實例里使用
defineExpose({ initExp })

  在 vue3.x 的 setup 語法糖中定義的變量默認不會暴露出去,這時使用 definExpose({ })來暴露組件內部屬性給父組件使用,在父組件中直接修改子組件的屬性,子組件也會相應更新。

// 子組件
<script setup> let aaa = ref("aaa") defineExpose({ aaa }); </script>

// 父組件
<Chlid ref="child"></Chlid>
<script setup> let child = ref(null) child.value.aaa //獲取子組件的aaa
</script>

二、官網:模板引用

  盡管存在 prop 和事件,但有時你可能仍然需要直接訪問 JavaScript 中的子組件。為此,可以使用 ref attribute 為子組件或 HTML 元素指定引用 ID。例如:

<input ref="input" />

  例如,你希望在組件掛載時,以編程的方式 focus 到這個 input 上,這可能有用(可以看到直接使用 this.$refs.input 就獲取到了 input Dom)

const app = Vue.createApp({}) app.component('base-input', { template: ` <input ref="input" /> `, methods: { focusInput() { this.$refs.input.focus() } }, mounted() { this.focusInput() } })

  此外,還可以向組件本身添加另一個 ref,並使用它從父組件觸發 focusInput 事件:

<base-input ref="usernameInput"></base-input>

this.$refs.usernameInput.focusInput()

  需要注意的是:$refs 只會在組件渲染完成之后生效(也就是生命周期 onMounted 之后)。這僅作為一個用於直接操作子元素的“逃生艙”——你應該避免在模板或計算屬性中訪問 $refs

三、官網:在組合式 API 中使用 template refs

  在使用組合式 API 時,響應式引用模板引用的概念是統一的。為了獲得對模板內元素或組件實例的引用,我們可以像往常一樣聲明 ref 並從 setup() 返回:

<template> 
  <div ref="root">This is a root element</div>
</template>
<script> import { ref, onMounted } from 'vue' export default { setup() { const root = ref(null) onMounted(() => { // DOM 元素將在初始渲染后分配給 ref
        console.log(root.value) // <div>This is a root element</div>
 }) return { root } } } </script>

  這里我們在渲染上下文中暴露 root,並通過 ref="root",將其綁定到 div 作為其 ref。在虛擬 DOM 補丁算法中,如果 VNode 的 ref 鍵對應於渲染上下文中的 ref,則 VNode 的相應元素或組件實例將被分配給該 ref 的值這是在虛擬 DOM 掛載/打補丁過程中執行的,因此模板引用只會在初始渲染之后獲得賦值

  作為模板使用的 ref 的行為與任何其他 ref 一樣:它們是響應式的,可以傳遞到 (或從中返回) 復合函數中

1、v-for 中的用法(for循環中如何獲取及重置refs)

  組合式 API 模板引用在 v-for 內部使用時沒有特殊處理。相反,請使用函數引用執行自定義處理

<template>
  <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }"> {{ item }} </div>
</template>
<script> import { ref, reactive, onBeforeUpdate } from 'vue' export default { setup() { const list = reactive([1, 2, 3]) const divs = ref([]) // 確保在每次更新之前重置ref
      onBeforeUpdate(() => { divs.value = [] }) return { list, divs } } } </script>

2、偵聽模板引用:偵聽模板引用的變更可以替代前面例子中演示使用的生命周期鈎子。

  但與生命周期鈎子的一個關鍵區別是,watch()watchEffect() 在 DOM 掛載或更新之前運行副作用,所以當偵聽器運行時,模板引用還未被更新

const root = ref(null) watchEffect(() => {   // 這個副作用在 DOM 更新之前運行,因此,模板引用還沒有持有對元素的引用。
  console.log(root.value) // => null
})

  因此,使用模板引用的偵聽器應該用 flush: 'post' 選項來定義,這將在 DOM 更新運行副作用,確保模板引用與 DOM 保持同步,並引用正確的元素

watchEffect(() => {   console.log(root.value) // => <div>This is a root element</div>
  },   {     flush: 'post'   })

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM