你不知道的 Vue3 中获取 DOM 节点或组件实例还能这么玩

在这里插入图片描述

在这里插入图片描述

基本模板引用

虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。 而在Vue 环境中通过原生的 document 去获取会存在一些问题,所以在 Vue3 中我们通过在标签节点上定义一个 ref 属性来得到我们想要的节点。

  • 类型:string | Function
  • ref :用于注册标签元素子组件 的引用对象。

如果使用的是选项式 API,引用将被注册在组件的 this.$refs 对象里:

<p ref="p">hello</p>

如果使用的是组合式 API,引用将存储在与名字匹配的 ref 数据变量里:

<template>
  <p ref="p">hello</p>
</template>

<script setup>
import { ref } from 'vue'

// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const p = ref()
</script>


如果不使用 <script setup> 语法糖,需确保从 setup()函数 返回 ref

export default {
  setup() {
    const p = ref(null)
    // ...
    return {
      p
    }
  }
}

可以直接拿到 DOM 标签节点
在这里插入图片描述

注意

你只能在组件挂载完成后 (onMounted()函数成功调用后)才能访问模板引用。如果你想在模板中的表达式上访问该 DOM 元素,在初次渲染时会是 null。这是因为在初次渲染前这个时间阶段元素还未创建且不存在呢

  • 如果你需要侦听一个模板引用 ref 的变化,确保考虑到其值会为 null 的情况:
watchEffect(() => {
  if (p.value) {
      console.log(p.value);
  } else {
    // 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)
  }
})

v-for 中的模板引用

  • 需要 Vue3 的 3.2.25 及以上版本才能支持
  • 当在 v-for 中使用模板引用获取DOM元素时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有标签元素:
<template>
  <ul>
    <li v-for="item in list" ref="itemRefs">
      {{ item }}
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted } from 'vue'
const list = ref([1, 2, 3])
const itemRefs = ref([])
onMounted(() => console.log(itemRefs.value))
</script>

在这里插入图片描述

  • 应该注意的是,ref 数组并不保证与源数组相同的顺序。

函数模板引用

推荐使用函数模板引用的方式)灵活性最高!也是作者我喜欢用的方式

除了使用字符串值作名字,ref 还可以绑定为一个函数方法,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数

<template>
    <input :ref="dok">
</template>
<script setup lang="ts" name="Box">
import { ref } from "vue";
let b = ref<HTMLInputElement | null>(null)
const dok = (el: HTMLInputElement): undefined => {
    console.log(el);
    b.value = el;//得到元素标签节点 ,并赋值给 b 属性保存起来。
}
</script>
  • 注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null。你当然也可以绑定一个内联函数或函数方法,这是可选的。

组件模板引用

  • ref如果用于普通 DOM 元素,引用将是元素本身;如果用于子组件,引用得到的值将是子组件的实例对象
<template>
    <Box ref="dom"></Box>
</template>

<script setup lang="ts" name="RootApp">
import Box from "/@/views/box/index.vue"
import { ref, onMounted } from "vue";

let dom = ref<InstanceType<typeof Box> | null>(null)

onMounted(() => {
    console.log(dom.value);
})

组件实例对象
在这里插入图片描述

组件引用说明

如果一个子组件使用的是选项式 API 或没有使用 <script setup> 语法糖,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互

  • 对使用了 <script setup> 语法糖 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 语法糖 的子组件中的任何声明的绑定,除非子组件在其中通过 defineExpose 宏函数显式的暴露要公开的属性值:
<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
  a,
  b
})
</script>

在这里插入图片描述

  • 当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number } (ref 都会自动解包,和一般的实例一样)。

在父组件加载完成后,就可以读取到子组件实例上暴露的值。

onMounted(() => {
    console.log(dom.value);
    console.log(dom.value.a);  //1
    console.log(dom.value.b);  //2
})

为模板引用标注类型

  • 模板引用需要通过一个显式指定的泛型参数和一个初始值 null 来创建:

例:

<template>
  <input ref="el" />
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const el = ref<HTMLInputElement | null>(null)

onMounted(() => {
  el.value?.focus()
})
</script>


值得注意:

注意为了严格的类型安全,有必要在访问 el.value 时使用可选链或类型守卫。这是因为直到组件被挂载前,这个 ref 的值都是初始的 null,并且在由于 v-if 的行为将引用的元素卸载时也可以被设置为 null


为组件模板引用标注类型

  • 为了获取 组件Box 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置InstanceType 工具类型来获取其实例类型:

<template>
    <Box ref="dom"></Box>
</template>
<script setup lang="ts" name="RootApp">
import Box from "/@/views/box/index.vue"
import { ref } from "vue";
let dom = ref<InstanceType<typeof Box> | null>(null)

</script>
  • 如果组件的具体类型无法获得,或者你并不关心组件的具体类型,那么可以使用 ComponentPublicInstance。这只会包含所有组件都共享的属性。
<template>
    <Box ref="dom"></Box>
</template>
<script setup lang="ts" name="RootApp">
import Box from "/@/views/box/index.vue"
import { ref } from "vue";
import type { ComponentPublicInstance } from 'vue'
let dom = ref<ComponentPublicInstance | null>(null)
</script>

ComponentPublicInstance 共享类型示例:(部分)
在这里插入图片描述

在这里插入图片描述


🚵‍♂️ 博主座右铭:向阳而生,我还在路上!
——————————————————————————————
🚴博主想说:将持续性为社区输出自己的资源,同时也见证自己的进步!
——————————————————————————————
🤼‍♂️ 如果都看到这了,博主希望留下你的足迹!【📂收藏!👍点赞!✍️评论!】
——————————————————————————————

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
Vue3,可以使用`ref`函数来创建一个ref对象,并将其与DOM元素关联起来。然后,你可以使用`.value`来访问DOM元素。例如,你可以在`<div>`元素上使用`ref`属性来创建一个ref对象,然后在代码使用`ref.value`来获取DOM元素的引用。下面是一个示例代码: ```html <template> <div ref="myDiv"></div> </template> <script setup> import { ref, onMounted } from 'vue'; const myDiv = ref(null); onMounted(() => { console.log('获取dom元素', myDiv.value); }); </script> ``` 在这个示例,我们使用了`ref`函数创建了一个名为`myDiv`的ref对象,并将其与`<div>`元素关联起来。然后,在`onMounted`钩子函数,我们使用`myDiv.value`来获取DOM元素的引用,并进行相应的操作。 除了使用`ref`,在Vue3还可以使用`getCurrentInstance`函数来获取当前组件实例对象。通过该函数,你可以访问到当前组件实例对象的`refs`属性,从而获取到对应的DOM元素。以下是一个示例代码: ```html <template> <div ref="divDom"></div> </template> <script setup> import { ref, getCurrentInstance, onMounted } from 'vue'; const divDom = ref(null); onMounted(() => { console.log('获取dom元素', divDom); }); // 获取页面的实例对象 const pageInstance = getCurrentInstance(); // 获取dom节点对象 const tagDomObj = pageInstance.refs.divDom; </script> ``` 在这个示例,我们创建了一个名为`divDom`的ref对象,并将其与`<div>`元素关联起来。然后,在`onMounted`钩子函数,我们使用`divDom`来获取DOM元素的引用,并进行相应的操作。另外,我们使用`getCurrentInstance`函数来获取当前组件实例对象,并通过`pageInstance.refs.divDom`来获取`divDom`的引用。 综上所述,在Vue3,你可以使用`ref`函数或`getCurrentInstance`函数来获取DOM元素的引用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【Vue3】获取DOM节点的几种方式](https://blog.csdn.net/m0_62811051/article/details/128121082)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [vue3获取dom元素和操作](https://blog.csdn.net/weixin_42349568/article/details/122841372)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧梦星轨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值