掌握Vue3:开启高效前端开发之旅

发表时间: 2024-07-02 11:42

在Vue3框架的精彩世界时,ref是连接Vue响应式系统与底层DOM结构的桥梁。在Vue框架内应用ref特性,显著增强了代码的清晰度和可维护性,因为它明确指明了组件内部哪些元素或组件实例将被操作。回顾JavaScript中的DOM操作,在原生JS中,我们通常通过document.getElementById, document.querySelector等方法来选取页面上的DOM元素,随后直接调用这些元素的属性或方法来修改它们的状态。

例如,改变一个元素的文本内容可以这样做:

js

复制代码

let element = document.getElementById('myElement');element.textContent = '新的内容';

这种方法直接而有效,但在复杂的单页应用(SPA)中容易导致代码难以维护,尤其是当DOM结构频繁变动时。下面我将为大家介绍在Vue3如何使用功能更加强大且灵活的ref来实现DOM操作。

1. ref的基本使用

在Vue中,你可以通过在模板中定义ref属性,然后在组件的setup()函数中通过refs对象访问这些DOM元素。

js

复制代码

<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元素。

js

复制代码

<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元素的引用:

js

复制代码

<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)  }}// 父容器的refconst 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引用存储到一个数组里:

js

复制代码

<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实例的refs对象中,就会创建一个名为button的数组,数组中的每个元素分别对应一个按钮的DOM引用。点击“点击我获取按钮引用”的按钮时,handleClick方法会被调用,展示或操作这些按钮的引用。

总结

ref的优势

  1. 响应式友好:Vue的ref与Vue的响应式系统紧密结合,这意味着当引用的DOM元素发生变化时,Vue能自动处理相关的更新逻辑。
  2. 代码清晰:通过在模板中明确标注ref,提高了代码的可读性和维护性,团队成员可以快速定位和理解哪些元素会被操作。
  3. 生命周期集成:Vue提供了如onMounted等生命周期钩子,确保DOM操作在合适的时机执行,避免了未挂载元素的访问错误。
  4. 组件化思维:与Vue的组件体系完美融合,使得在组件间传递和操作DOM引用变得更加自然和高效。