当前位置:首页 > 技术文章 > 正文内容

Vue3 超进化:两个改变编码习惯的高级技巧

zonemu3个月前 (07-13)技术文章37

有这两个能够帮我们“打通任督二脉”的Vue3高级技巧,掌握它们,将提高我们对底层原理的理解以及解决复杂问题的能力

封装的艺术 —— 随心所欲地创建 Composable函数 (useXXX)

Composable是一个利用Vue组合式API来封装和复用有状态逻辑的函数。按照惯例,我们通常以use开头命名,例如useMousePositionuseFetch。它不是一个特定的API,而是一种代码组织模式。

  • 告别Mixin的混乱:相比Vue2的Mixin,Composable的来源清晰,不存在命名冲突问题,类型推导也更友好。我们知道每一个响应式状态和方法都来自于哪个use函数。
  • 逻辑内聚,关注点分离:我们可以将一个复杂组件中的不同逻辑(如数据请求、事件监听、动画控制)拆分到不同的Composable中,让组件的<script setup>部分变得异常清爽,只负责“组织”逻辑,而非“实现”逻辑。

创建一个useDebouncedRef

假设我们有一个搜索框,希望在用户停止输入500毫秒后再去请求API,以避免频繁的请求。这个“防抖”逻辑在很多地方都会用到。

1. 创建 useDebouncedRef.ts

// composables/useDebouncedRef.ts
import { customRef } from 'vue';

/**
 * 创建一个防抖的 ref
 * @param value 初始值
 * @param delay 延迟毫秒数, 默认 500ms
 */
export function useDebouncedRef<T>(value: T, delay = 500) {
  let timeout: number;
  // customRef 是一个强大的API, 允许我们完全控制 ref 的依赖跟踪和更新触发
  return customRef((track, trigger) => {
    return {
      get() {
        track(); // 告诉Vue, 这个值被读取了, 需要追踪依赖
        return value;
      },
      set(newValue: T) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          value = newValue;
          trigger(); // 告诉Vue, 值已经改变, 请更新DOM
        }, delay);
      },
    };
  });
}

注意: 这里我们顺便用到了下一个技巧的核心API customRef,稍后会详细讲解。

2. 在组件中使用

<template>
  <input v-model="searchText" placeholder="输入后500ms触发更新..." />
  <p>Debounced Value: {{ searchText }}</p>
</template>

<script setup lang="ts">
import { useDebouncedRef } from './composables/useDebouncedRef';

// 使用起来就像一个普通的 ref,但它自带防抖功能!
const searchText = useDebouncedRef('', 500);

// 我们可以像往常一样 watch 它,回调只会在防抖后执行
// watch(searchText, (newValue) => {
//   console.log('向服务器发起请求: ', newValue);
// });
</script>

掌控响应式 —— 玩转customRef与shallowRef

在熟练掌握 refreactive 之后,随着复杂功能或优化性能的出现,需要在必要时“绕过”或“定制”Vue的默认深度响应式行为。

  • customRef: 创建一个自定义的ref,并对其依赖跟踪和更新触发进行显式控制。我们上面的useDebouncedRef就是最佳范例。
  • shallowRef: 创建一个只对.value的赋值操作是响应式的ref。其内部的值不会被深层地转换为响应式对象。
  • customRef体现了我们对响应式原理的理解:我们知道响应式系统工作的两个核心是track()(依赖收集)和trigger()(更新触发)。能够使用customRef意味着我们已经从API使用者变成了API“创造者”。
  • shallowRef是性能优化的利器:当我们有大型的、不可变的数据结构时(例如一个巨大的JSON对象、一个第三方库的实例),使用ref会对其进行深度递归代理,造成不必要的性能开销。此时shallowRef就是最佳选择。

使用shallowRef优化大型数据

假设我们需要引入一个庞大的图表库实例,这个实例本身有很多内部属性,但我们只关心实例本身是否被替换。

<template>
  <div ref="chartContainer"></div>
</template>

<script setup lang="ts">
import { onMounted, shallowRef, ref, triggerRef } from 'vue';
import SomeHeavyChartLibrary from 'some-heavy-chart-library';

// 使用 shallowRef, Vue 不会尝试代理 aChartInstance 内部的所有属性
const chartInstance = shallowRef(null);
const chartContainer = ref(null);

onMounted(() => {
  // aChartInstance 的赋值是响应式的
  chartInstance.value = new SomeHeavyChartLibrary(chartContainer.value);
});

function updateChartWithOptions(newOptions) {
  if (chartInstance.value) {
    // chartInstance 内部属性的改变不会触发更新
    chartInstance.value.setOptions(newOptions);

    // 如果我们确实需要手动强制更新,可以使用 triggerRef
    // triggerRef(chartInstance);
  }
}
</script>

将这两个技巧融入我们的日常开发中,刻意练习,我们的代码质量和个人技术深度,必将迈上一个新的台阶。

相关文章

Ubuntu 24.10发行版登场:Linux 6.11内核、GNOME 47桌面环境

IT之家 10 月 11 日消息,Canonical 昨日发布新闻稿,正式推出代号为 Oracular Oriole 的 Ubuntu 24.10 发行版。新版在内核方面升级到最新 6.11 版本,并...

【Vue3 基础】05.组件化(组件使用vuex)

这是 Vue3 + Vite + Pinia +TS + Element-Plus 实战系列文档。最近比较忙没什么时间写文章,争取早日把这个系列完结吧~生命周期和模板引用在本章之前,我们通过响应式 a...

Vue3 中有哪些值得深究的知识点?(vue3例子)

众所周知,前端技术一直更新很快,这不 vue3 也问世这么久了,今天就来给大家分享下vue3中值得注意的知识点。喜欢的话建议收藏,点个关注!1、createAppvue2 和 vue3 在创建实例时,...

程序员项目经理如何调动组员积极性

#这个方法应该很适合程序员都说程序员是比较傲娇,有点小自负(有的是相当,那不叫自负,那是实力的体现好吗),略微呆萌,自尊心偏小强的一类族群。是吗?中招了吗?作为管理好几个组员,要完成一个大项目的项目经...

Java教程:GitLab在项目的环境搭建和基本的使用

gitlab-使用入门1 导读本教程主要讲解了GitLab在项目的环境搭建和基本的使用,可以帮助大家在企业中能够自主搭建GitLab服务,并且可以GitLab中的组、权限、项目自主操作GitLab简介...

(在线编辑DWG)网页CAD二开实现焊接符号绘制

前言在工程制图和制造领域,焊接符号(Welding Symbols)是用于表示焊缝类型、尺寸、位置以及工艺要求的标准化图形语言。广泛应用于机械设计、钢结构、船舶制造、压力容器等行业中,帮助技术人员理解...