一篇文章搞懂Vue3中如何使用ref獲取元素節(jié)點
前言
雖然在 Vue 中不提倡我們直接操作 DOM,畢竟 Vue 的理念是以數(shù)據(jù)驅(qū)動視圖。但是在實際情況中,我們有很多需求都是需要直接操作 DOM 節(jié)點的,這個時候 Vue 提供了一種方式讓我們可以獲取 DOM 節(jié)點:ref 屬性。ref 屬性是 Vue2 和 Vue3 中都有的,但是使用方式卻不大一樣,這也導(dǎo)致了很多從 Vue2 轉(zhuǎn)到 Vue3 的小伙伴感到有些困惑。
今天我們就來揭開 Vue3 中 ref 的神秘面紗!
1.回顧 Vue2 中的 ref
在學習 Vue3 中的 ref 之前,我們先來了解下 Vue2 中 ref,這樣一對比,大家更能夠加深印象,以及它們之間的區(qū)別。
獲取節(jié)點:
這是 ref 的基本功能之一,目的就是獲取元素節(jié)點,在 Vue 中使用方式也很簡單,代碼如下:
<template> <div id="app"> <div ref="hello">小豬</div> </div> </template> <script> export default { mounted() { console.log(this.$refs.hello); // <div>小豬</div> }, }; </script>
上段代碼中可以看到我們在 div 元素上綁定了 ref 屬性,并命名為 hello,接下來我們直接使用 this.$refs.hello 的方式就可以獲取到該 DOM 元素了。
2.Vue3 中 ref 訪問元素
Vue3 中通過 ref 訪問元素節(jié)點與 Vue2 不太一樣,在 Vue3 中我們是沒有 this 的,所以當然也沒有 this.$refs。想要獲取 ref,我們只能通過聲明變量的方式。
創(chuàng)建一個 Vite 項目:
為了方便演示,我們直接在 Vite 項目中演示 ref 代碼,創(chuàng)建項目指令如下:
npm create vite@latest my-vue-app --template vue-ts
代碼如下:
<template> <div ref="hello">小豬課堂</div> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; const hello = ref<any>(null); onMounted(() => { console.log(hello.value); // <div>小豬課堂</div> }); </script>
輸出結(jié)果:
上段代碼中我們同樣給 div 元素添加了 ref 屬性,為了獲取到這個元素,我們聲明了一個與 ref 屬性名稱相同的變量 hello,然后我們通過 hello.value 的形式便獲取到了該 div 元素。
注意點:
- 變量名稱必須要與 ref 命名的屬性名稱一致。
- 通過 hello.value 的形式獲取 DOM 元素。
- 必須要在 DOM 渲染完成后才可以獲取 hello.value,否則就是 null。
3.v-for 中使用 ref
使用 ref 的場景有多種,一種是單獨綁定在某一個元素節(jié)點上,另一種便是綁定在 v-for 循環(huán)出來的元素上了。這是一種非常常見的需求,在 Vue2 中我們通常使用:ref="…"的形式,只要能夠標識出每個 ref 不一樣即可。
但是在 Vue3 中又不太一樣,不過還是可以通過變量的形式接收。
代碼如下:
<template> <div ref="hello">小豬課堂</div> <ul> <li v-for="item in 10" ref="itemRefs"> {{item}} - 小豬課堂 </li> </ul> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; const itemRefs = ref<any>([]); onMounted(() => { console.log(itemRefs.value); }); </script>
輸出結(jié)果:
段代碼中盡管是 v-for 循環(huán),但是我們似乎使用 ref 的形式與第 2 節(jié)中的方式?jīng)]有任何變化,我們同樣使用變量的形式拿到了每一個 li 標簽元素。
但是這里我們需要注意一下:我們似乎沒辦法區(qū)分哪個 li 標簽?zāi)膫€ ref,初次之外,我們的 itemRefs 數(shù)組不能夠保證與原數(shù)組順序相同,即與 list 原數(shù)組中的元素一一對應(yīng)。
4.ref 綁定函數(shù)
前面我們在組件上定義 ref 時,都是以一個字符串的形式作為 ref 的名字,其實我們的 ref 屬性還可以接收一個函數(shù)作為屬性值,這個時候我們需要在 ref 前面加上:。
代碼如下:
<template> <div :ref="setHelloRef">小豬課堂</div> </template> <script setup lang="ts"> import { ComponentPublicInstance, HTMLAttributes } from "vue"; const setHelloRef = (el: HTMLElement | ComponentPublicInstance | HTMLAttributes) => { console.log(el); // <div>小豬課堂</div> }; </script>
輸出結(jié)果:
上段代碼中 ref 屬性接收的是一個 setHelloRef 函數(shù),該函數(shù)會默認接收一個 el 參數(shù),這個參數(shù)就是我們需要獲取的 div 元素。假如需求中我們采用這種方式的話,那么完全可以把 el 保存到一個變量中去,供后面使用。
那么,我們在 v-for 中是否也能采用這種方式呢?
答案是可以的!
v-for 中使用
代碼如下:
<template> <ul> <li v-for="item in 10" :ref="(el) => setItemRefs(el, item)"> {{ item }} - 小豬課堂 </li> </ul> </template> <script setup lang="ts"> import { ComponentPublicInstance, HTMLAttributes, onMounted } from "vue"; let itemRefs: Array<any> = []; const setItemRefs = (el: HTMLElement | ComponentPublicInstance | HTMLAttributes, item:number) => { if(el) { itemRefs.push({ id: item, el, }); } } onMounted(() => { console.log(itemRefs); }); </script>
輸出結(jié)果:
在 v-for 中使用函數(shù)的形式傳入 ref 與不使用 v-for 時的形式差不多,不過這里我們做了一點變通,為了區(qū)別出哪個 ref 是哪一個 li 標簽,我們決定將 item 傳入函數(shù),也就是(el) => setItemRefs(el, item)的寫法。
這種形式的好處既讓我們的操作性變得更大,還解決了 v-for 循環(huán)是 ref 數(shù)組與原數(shù)組順序不對應(yīng)的問題。
5.組件上使用 ref
前面我們所使用 ref 時,都是在一個具體的 dom 元素上綁定,但是我們也可以將 ref 綁定在組件上,比如在 Vue2 中,我們將 ref 綁定在組件上時,便可以獲取到該組件里面的所有數(shù)據(jù)和方法.
雖然 Vue3 中也可以將 ref 綁定在組件上,但是具體能獲取組件的哪些值還是有一些區(qū)別的,我們一起來看看。
代碼如下:
<template> <child ref="childRef"></child> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; import child from "./child.vue"; const childRef = ref<any>(null); onMounted(() => { console.log(childRef.value); // child 組件實例 console.log(childRef.value.message); // undefined }); </script>
子組件 child 代碼:
<template> <div>{{ message }}</div> </template> <script lang="ts" setup> import { ref } from "vue"; const message = ref<string>("我是子組件"); const onChange = () => {}; </script>
輸出結(jié)果:
上段代碼中我們新增了一個子組件,然后再子組件上面綁定了 ref,其用法基本上和 ref 直接綁定在 DOM 元素上一致。
但是如果我們把 ref 綁定再組件上,通常就是為了調(diào)用子組件里面的方法或者數(shù)據(jù),可是從上面的輸出結(jié)果來看,我們沒有獲取到數(shù)據(jù),即 childRef.value.message 為 undefined,這也是與 Vue2 的不同之處。
在 Vue3 中,使用 ref 獲取子組件時,如果想要獲取子組件的數(shù)據(jù)或者方法,子組件可以通過
defineExpose 方法暴露數(shù)據(jù)。
修改子組件代碼:
<template> <div>{{ message }}</div> </template> <script lang="ts" setup> import { ref } from "vue"; const message = ref<string>("我是子組件"); const onChange = () => { console.log("我是子組件方法") }; defineExpose({ message, onChange }); </script>
父組件再次獲取:
const childRef = ref<any>(null); onMounted(() => { console.log(childRef.value); // child 組件實例 console.log(childRef.value.message); // 我是子組件 childRef.value.onChange(); // 我是子組件方法 });
輸出結(jié)果:
可以看到我們在父組件中可以獲取到子組件暴露的數(shù)據(jù)和方法了。
總結(jié)
雖然 Vue2 和 Vue3 中的 ref 使用方式有著較大的區(qū)別,但是它們的目的都是一樣的,所以我們只要朝著目的前進,都會與美好相遇的!
到此這篇關(guān)于通過一篇文章搞懂Vue3中如何使用ref獲取元素節(jié)點的文章就介紹到這了,更多相關(guān)Vue3用ref獲取元素節(jié)點內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nuxt.js中間件實現(xiàn)攔截權(quán)限判斷的方法
這篇文章主要介紹了nuxt.js中間件實現(xiàn)攔截權(quán)限判斷的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11vue用戶長時間不操作退出到登錄頁的兩種實現(xiàn)方式
出于安全考慮,用戶長時間不操作,就回到登錄頁面,讓用戶重新登錄,本文就記錄一下實現(xiàn)這種效果的兩種方式,具有一定的參考價值,感興趣的可以了解一下2021-09-09vue中v-if?和v-permission?共同使用的坑及解決方案
這篇文章主要介紹了vue中v-if?和v-permission?共同使用的坑及解決方案的相關(guān)資料,需要的朋友可以參考下2023-07-07