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

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

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

推荐文章

解决 PHP 中的 HTTP 请求超时问题
2024-11-19 09:10:35 +0800 CST
Nginx 性能优化有这篇就够了!
2024-11-19 01:57:41 +0800 CST
2024年公司官方网站建设费用解析
2024-11-18 20:21:19 +0800 CST
一个收银台的HTML
2025-01-17 16:15:32 +0800 CST
程序员茄子在线接单