你会用JS进行DOM操作,Vue3呢?
前言
在Vue3框架的精彩世界时,ref是连接Vue响应式系统与底层DOM结构的桥梁。在Vue框架内应用ref
特性,显著增强了代码的清晰度和可维护性,因为它明确指明了组件内部哪些元素或组件实例将被操作。回顾JavaScript中的DOM操作,在原生JS中,我们通常通过document.getElementById
, document.querySelector
等方法来选取页面上的DOM元素,随后直接调用这些元素的属性或方法来修改它们的状态。
例如,改变一个元素的文本内容可以这样做:
let element = document.getElementById('myElement');
element.textContent = '新的内容';
这种方法直接而有效,但在复杂的单页应用(SPA)中容易导致代码难以维护,尤其是当DOM结构频繁变动时。下面我将为大家介绍在Vue3如何使用功能更加强大且灵活的ref
来实现DOM操作。
1. ref的基本使用
在Vue中,你可以通过在模板中定义ref
属性,然后在组件的setup()
函数中通过refs
对象访问这些DOM元素。
<template>
<div>
<p ref="myParagraph">原始内容</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
onMounted(() => {
// 使用ref获取DOM元素
const myParagraph = ref(null);
// 确保DOM已挂载后操作
if (myParagraph.value) {
myParagraph.value.textContent = '通过Vue ref修改的内容';
}
});
</script>
在该组件成功挂载之后,p标签中的内容将会被替换。
错误的使用示范
在使用ref访问DOM时,尝试在Vue组件的setup
函数外部或在不恰当的生命周期阶段访问通过ref
定义的DOM元素。
<template>
<div ref="exampleRef">Hello Vue!</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const exampleRef = ref(null);
// 尝试在setup函数内部立即访问DOM,但此时DOM还未挂载
console.log(exampleRef.value); // 输出: null,因为此时DOM还没被挂载
// 或者错误地在一个定时器中尝试访问,即使在mounted之后,但未确保DOM访问时机
setTimeout(() => {
console.log(exampleRef.value); // 可能输出null,取决于定时器执行时机与DOM挂载完成的相对时间
}, 1000);
</script>
在这段错误的使用ref的示范中我们可以看到,ref访问DOM元素时并不能立即访问,必须要等待DOM成功挂载之后再进行访问,否则会报错。
2. ref的应用场景
获取多个子元素的DOM引用
在Vue3,如果需要通过父容器的ref
遍历其下的多个子元素获取DOM引用,通常是使用v-for
循环生成一组DOM元素,然后定义一个父容器的ref
,并通过它来遍历获取内部由v-for
生成的DOM元素的引用:
<template>
<div ref="parentContainer">
<div v-for="(item, index) in items" :key="index" :ref="setChildRef">
{{ item }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 假设items是你的数据源
const items = ref(['Item 1', 'Item 2', 'Item 3'])
// 定义一个方法来收集子元素的引用
const childRefs = ref([]) as any // 类型断言,根据实际类型调整
const setChildRef = (el: HTMLElement | undefined) => {
if (el) {
childRefs.value.push(el)
}
}
// 父容器的ref
const parentContainer = ref(null)
onMounted(() => {
// 在组件挂载完成后,可以通过parentContainer.value直接访问父容器的DOM
console.log('Parent Container:', parentContainer.value)
// 遍历并操作子元素的DOM引用
childRefs.value.forEach((childRef, index) => {
console.log(`Child ${index + 1} DOM Element:`, childRef)
// 这里可以对每个childRef执行DOM操作,例如设置样式等
})
})
</script>
在这个例子中,setChildRef
方法会在每个循环生成的元素上被调用,并将DOM元素的引用收集到childRefs
数组中。然后在onMounted
生命周期钩子中,你可以遍历childRefs
数组,对每个子元素的DOM进行操作。注意,使用:ref
结合一个方法时,需要在方法名前加上冒号(`:》来表示这是一个动态绑定。
收集DOM引用
在Vue中,使用:ref属性可以将DOM元素或者子组件的实例绑定到父组件的this.$refs对象上。如果:ref用在循环中,绑定的元素或组件实例会自动收集到一个数组中。下面是一个具体的实例,演示如何将一组由v-for生成的按钮的DOM引用存储到一个数组里:
<template>
<div>
<button v-for="(item, index) in items" :key="index" :ref="`button-${index}`">
Button {{ item }}
</button>
<button @click="handleClick">点击我获取按钮引用</button>
</div>
</template>
<script>
export default {
data() {
return {
items: [1, 2, 3, 4, 5], // 假设这是你的数据列表
};
},
methods: {
handleClick() {
// 使用this.$refs获取所有按钮的引用
console.log(this.$refs['button']);
// 如果你想对这些按钮做些什么,比如改变第一个按钮的文字颜色
// 注意:实际操作中应确保DOM操作的安全性,这里仅为示例
this.$refs['button'][0].style.color = 'red';
},
},
};
</script>
在这个例子中,每个按钮都有一个动态的:ref属性,形式为button-index,这样在Vue实例的{index},这样在Vue实例的index,这样在Vue实例的refs对象中,就会创建一个名为button的数组,数组中的每个元素分别对应一个按钮的DOM引用。点击“点击我获取按钮引用”的按钮时,handleClick方法会被调用,展示或操作这些按钮的引用。
总结
ref
的优势
- 响应式友好:Vue的
ref
与Vue的响应式系统紧密结合,这意味着当引用的DOM元素发生变化时,Vue能自动处理相关的更新逻辑。 - 代码清晰:通过在模板中明确标注
ref
,提高了代码的可读性和维护性,团队成员可以快速定位和理解哪些元素会被操作。 - 生命周期集成:Vue提供了如
onMounted
等生命周期钩子,确保DOM操作在合适的时机执行,避免了未挂载元素的访问错误。 - 组件化思维:与Vue的组件体系完美融合,使得在组件间传递和操作DOM引用变得更加自然和高效。
本篇文章就到此为止啦,希望通过这篇文章能对你理解Vue3中使用ref进行DOM操作
有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。
转载自:https://juejin.cn/post/7386514632726134818