Vue2的方法
Vue2可以使用ref属性和this.$refs去获取DOM,但是不同情况下会有些许区别。
- ref 在 html 标签上
<div ref="myDom"></div>
此时可以直接取到DOM对象:
this.$refs.myDom // 拿到DOM对象
- ref 在 vue 组件上
<HelloWorld ref="myComp" msg="Welcome to Your Vue.js App"/>
此时拿到的是vue组件对象,需要再访问$el属性才能拿到DOM对象:
this.$refs.myComp // 拿到组件对象
this.$refs.myComp.$el // 拿到DOM对象
- ref 在 v-for 中使用
<div v-for="(item,index) in list" :key="item" :ref="'myArr' + index"></div>
在v-for中使用的ref,取到的都是一个数组,需要访问第一个元素才能拿到DOM对象;
this.$refs.myArr0 // 这是数组
this.$refs.myArr0[0] // 拿到第一个div的DOM对象
Vue3的方法
Vue3也是使用ref去定义DOM,但是Vue3中,组件中的this并不是指向组件对象,因此不能使用this.$refs去访问DOM,但Vue3中,提供了更简洁的方式去获取DOM
- 上述的例子,在Vue3中是这样的访问和输出:
const myDom = ref(null)
const myComp = ref(null)
const myArr0 = ref(null)
console.log(unref(myDom)) // 拿到DOM对象
console.log(unref(myComp)) // 组件的proxy
console.log(unref(myComp).$el) // 组件的DOM对象
console.log(unref(myArr0)) // 数组的代理
console.log(unref(myArr0)[0]) // DOM对象
- 我们发现,当在v-for中使用ref的时候,在Vue3中需要定义很多个变量,非常不方便。ref属性实际上也可以接收一个函数,函数的参数就是我们需要的DOM对象。
<div :ref="getMyDom"></div>
<div v-for="(item,index) in list" :key="item" :ref="getMyArr">{{index}}</div>
function getMyDom(el) {
console.log(el) // 拿到DOM对象
}
function getMyArr(el) {
console.log(el) // 按顺序输出了div对象
}
Vue3的ref封装
我们可以定义一个hooks,将获取DOM的方法封装起来:
useRefs.ts:代码来自于vben-admin
import type { Ref } from 'vue';
import { ref, onBeforeUpdate } from 'vue';
export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] {
const refs = ref([]) as Ref<HTMLElement[]>;
onBeforeUpdate(() => {
refs.value = [];
});
const setRefs = (index: number) => (el: HTMLElement) => {
refs.value[index] = el;
};
return [refs, setRefs];
}
注意这里的setRefs,返回值是一个函数,因此我们在template中使用的时候,是:ref="setRefs(index)",这样就能把DOM传给setRefs(index)函数了,然后这个DOM会存到refs变量里。
使用方法:
<ul>
<li
:ref="setRefs(index)"
v-for="(item, index) in searchResult"
</li>
</ul>
import { useRefs } from '/@/hooks/core/useRefs';
const [refs, setRefs] = useRefs();
console.log(refs.value) // refs是一个数组,按顺序把li的DOM放到这个数组里了。