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

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

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

推荐文章

Go 接口:从入门到精通
2024-11-18 07:10:00 +0800 CST
JS 箭头函数
2024-11-17 19:09:58 +0800 CST
Nginx 性能优化有这篇就够了!
2024-11-19 01:57:41 +0800 CST
基于Webman + Vue3中后台框架SaiAdmin
2024-11-19 09:47:53 +0800 CST
初学者的 Rust Web 开发指南
2024-11-18 10:51:35 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
一个有趣的进度条
2024-11-19 09:56:04 +0800 CST
Rust 高性能 XML 读写库
2024-11-19 07:50:32 +0800 CST
Nginx 防止IP伪造,绕过IP限制
2025-01-15 09:44:42 +0800 CST
Go语言SQL操作实战
2024-11-18 19:30:51 +0800 CST
服务器购买推荐
2024-11-18 23:48:02 +0800 CST
PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
前端代码规范 - Commit 提交规范
2024-11-18 10:18:08 +0800 CST
Elasticsearch 文档操作
2024-11-18 12:36:01 +0800 CST
PHP设计模式:单例模式
2024-11-18 18:31:43 +0800 CST
jQuery `$.extend()` 用法总结
2024-11-19 02:12:45 +0800 CST
XSS攻击是什么?
2024-11-19 02:10:07 +0800 CST
2024年公司官方网站建设费用解析
2024-11-18 20:21:19 +0800 CST
Vue3如何执行响应式数据绑定?
2024-11-18 12:31:22 +0800 CST
SQL常用优化的技巧
2024-11-18 15:56:06 +0800 CST
程序员茄子在线接单