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

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

全网首发: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

推荐文章

Vue3中如何处理权限控制?
2024-11-18 05:36:30 +0800 CST
Java环境中使用Elasticsearch
2024-11-18 22:46:32 +0800 CST
18个实用的 JavaScript 函数
2024-11-17 18:10:35 +0800 CST
php机器学习神经网络库
2024-11-19 09:03:47 +0800 CST
WebSQL数据库:HTML5的非标准伴侣
2024-11-18 22:44:20 +0800 CST
如何使用go-redis库与Redis数据库
2024-11-17 04:52:02 +0800 CST
地图标注管理系统
2024-11-19 09:14:52 +0800 CST
imap_open绕过exec禁用的脚本
2024-11-17 05:01:58 +0800 CST
Elasticsearch 文档操作
2024-11-18 12:36:01 +0800 CST
Vue3中的自定义指令有哪些变化?
2024-11-18 07:48:06 +0800 CST
Python设计模式之工厂模式详解
2024-11-19 09:36:23 +0800 CST
为什么要放弃UUID作为MySQL主键?
2024-11-18 23:33:07 +0800 CST
MySQL 日志详解
2024-11-19 02:17:30 +0800 CST
gin整合go-assets进行打包模版文件
2024-11-18 09:48:51 +0800 CST
PHP 如何输出带微秒的时间
2024-11-18 01:58:41 +0800 CST
程序员茄子在线接单