综合 全网首发:Vue 3.5 源码解析,useTemplateRef 实现原理

2024-11-19 09:30:11 +0800 CST views 1010

全网首发:Vue 3.5 源码解析,useTemplateRef 实现原理

2024年9月3日,Vue 3.5 的正式版终于发布了。
images
前几天我们分享了 Vue 3.5 的新特性,其中 useTemplateRef 这个 API 备受关注。那么,它在源码中究竟是如何实现的呢?今天我们就来一探究竟!

useTemplateRef 的作用

useTemplateRef 是用来专门获取 DOM 或组件实例的。

在 Vue 3.5 之前,如果我们想获取 DOM 实例,通常会这样做:

  1. 为 DOM 指定 ref 属性,并赋予一个值。
  2. 在 JavaScript 中声明一个 ref 变量,并初始化为空。
<script setup>
// 定义一个 ref,初始值为空
const divEl = ref();
</script>

<template>
  <!-- 使用 ref 绑定 DOM -->
  <div ref="divEl"></div>
</template>

这种方式有一个问题:ref 通常用于声明响应式数据,而当它同时被用作获取 DOM 实例时,容易让人产生混淆。因此,在 Vue 3.5 之后,推出了 useTemplateRef API 以解决这个问题:

<template>
  <div ref="el">程序员Sunday</div>
</template>

<script setup>
import { onMounted, useTemplateRef } from 'vue';

const elRef = useTemplateRef('el');

onMounted(() => {
  console.log(elRef.value); // 获取 DOM 实例
});
</script>

useTemplateRef 的实现原理

useTemplateRef 的实现本质上还是基于 ref,只是对其进行了封装。我们来看源码中的具体实现。

vue-next-3.5.0-master/packages/runtime-core/src/helpers/useTemplateRef.ts 文件下,可以看到 useTemplateRef 的实现逻辑。以下是经过简化后的代码:

export function useTemplateRef(key: Keys) {
  const i = getCurrentInstance();
  const r = shallowRef(null);
  
  if (i) {
    const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs;
    
    Object.defineProperty(refs, key, {
      enumerable: true,
      get: () => r.value,
      set: val => (r.value = val),
    });
  }
  
  return r;
}

代码解析

  1. 入参 key
    key 代表传入的 ref 值,例如在 useTemplateRef('el') 中,key 就是 'el'

  2. 获取上下文实例 i
    使用 getCurrentInstance() 获取当前上下文的实例 i,接着通过 i.refs 获取所有的 ref 数据。

  3. 定义 refs[key] 的 getter 和 setter
    refs 添加 Object.defineProperty,监听传入的 key 值。在 set 操作中,会为 r.value 赋值,也就是 refs[key] 的值(即 ref 的组件或 DOM 实例)。

  4. 返回 r
    通过 shallowRef(null) 创建一个浅响应的 ref 对象 r,并作为 useTemplateRef 的返回值。最终,我们可以通过 r.value 来获取对应的组件实例或 DOM 实例。

shallowRef 方法解析

shallowRef 是一种浅响应的 ref,只对其 value 属性进行响应。通过 shallowRef(null) 创建的 r 对象,其 value 属性会在 refs[key] 的 setter 触发时被赋值,即为 ref 对应的 DOM 或组件实例。

总结

useTemplateRef 的源码实现并不复杂,主要包括以下两步:

  1. 通过 Object.defineProperty 监听 refs[key] 的 setter 行为,为 r.value 赋值。
  2. 通过 shallowRef 生成 ref 实例,并作为 useTemplateRef 的返回值。

通过 useTemplateRef,我们可以方便地获取 DOM 或组件实例,避免了使用 ref 既声明响应式数据又绑定 DOM 实例带来的困惑。

复制全文 生成海报 Vue 前端开发 JavaScript

推荐文章

16.6k+ 开源精准 IP 地址库
2024-11-17 23:14:40 +0800 CST
PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
聚合支付管理系统
2025-07-23 13:33:30 +0800 CST
Rust 与 sqlx:数据库迁移实战指南
2024-11-19 02:38:49 +0800 CST
前端项目中图片的使用规范
2024-11-19 09:30:04 +0800 CST
PHP 命令行模式后台执行指南
2025-05-14 10:05:31 +0800 CST
Go中使用依赖注入的实用技巧
2024-11-19 00:24:20 +0800 CST
api接口怎么对接
2024-11-19 09:42:47 +0800 CST
开发外贸客户的推荐网站
2024-11-17 04:44:05 +0800 CST
Vue 3 中的 Fragments 是什么?
2024-11-17 17:05:46 +0800 CST
JavaScript设计模式:桥接模式
2024-11-18 19:03:40 +0800 CST
20个超实用的CSS动画库
2024-11-18 07:23:12 +0800 CST
记录一次服务器的优化对比
2024-11-19 09:18:23 +0800 CST
Vue3中如何处理组件间的动画?
2024-11-17 04:54:49 +0800 CST
使用Python实现邮件自动化
2024-11-18 20:18:14 +0800 CST
程序员茄子在线接单