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

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

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

推荐文章

Python 获取网络时间和本地时间
2024-11-18 21:53:35 +0800 CST
Vue3中如何处理WebSocket通信?
2024-11-19 09:50:58 +0800 CST
js函数常见的写法以及调用方法
2024-11-19 08:55:17 +0800 CST
Vue3中如何实现插件?
2024-11-18 04:27:04 +0800 CST
Golang 几种使用 Channel 的错误姿势
2024-11-19 01:42:18 +0800 CST
JavaScript中的常用浏览器API
2024-11-18 23:23:16 +0800 CST
SQL常用优化的技巧
2024-11-18 15:56:06 +0800 CST
html一些比较人使用的技巧和代码
2024-11-17 05:05:01 +0800 CST
Vue中如何处理异步更新DOM?
2024-11-18 22:38:53 +0800 CST
PHP如何进行MySQL数据备份?
2024-11-18 20:40:25 +0800 CST
JavaScript设计模式:单例模式
2024-11-18 10:57:41 +0800 CST
GROMACS:一个美轮美奂的C++库
2024-11-18 19:43:29 +0800 CST
如何实现虚拟滚动
2024-11-18 20:50:47 +0800 CST
php机器学习神经网络库
2024-11-19 09:03:47 +0800 CST
服务器购买推荐
2024-11-18 23:48:02 +0800 CST
Flet 构建跨平台应用的 Python 框架
2025-03-21 08:40:53 +0800 CST
ElasticSearch简介与安装指南
2024-11-19 02:17:38 +0800 CST
php curl并发代码
2024-11-18 01:45:03 +0800 CST
程序员茄子在线接单