所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Vue 3.5 重磅新特性:useTemplateRef 让模板引用更优雅、更高效!

概述

useTemplateRef 是 Vue 3.5 中引入的新组合式 API,提供更优雅的模板引用方式。

特性说明

主要优势

  • 类型安全: 完整 TypeScript 类型推断
  • 类型安全: 完整 TypeScript 类型推断
  • 更好的 IDE 支持: 准确的智能提示
  • 简化语法: 减少样板代码

使用示例

基础用法

<template>
  <div>
    <input ref="inputRef" type="text" />
    <button @click="focusInput">聚焦</button>
  </div>
</template>

<script setup lang="ts">
import { useTemplateRef } from "vue";

const inputRef = useTemplateRef("inputRef");

const focusInput = () => {
  inputRef.value?.focus();
};
</script>

vue3.5 之前的写法:

<template>
  <div>
    <input ref="inputRef" type="text" placeholder="" />
    <button @click="focusInput">聚焦</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

const inputRef = ref(null);

const focusInput = () => {
  inputRef.value.focus();
};
</script>

ref vs useTemplateRef

对比项refuseTemplateRef
引入版本Vue 3.0 原生支持Vue 3.5 新增 API
语法设计需手动声明变量名与模板 ref 属性值一致,易混淆通过函数参数显式绑定,避免命名冲突
类型支持需额外类型标注(如 ref)自动推断类型,减少类型声明冗余
实现原理直接创建响应式引用封装 shallowRef,优化性能与内存管理
IDE 支持基础智能提示更准确的智能提示和类型推断

性能优化

1. 内存与渲染效率提升

  • 内部封装 shallowRef 替代普通 ref,减少深层响应式代理的开销,内存占用降低 56%
  • 直接绑定 DOM 元素引用,避免传统 ref 的中间代理层,操作延迟减少 30%

2. 类型推断与代码精简

  • 自动推断模板引用的类型,省去手动标注(如 ref<HTMLInputElement>),减少冗余代码量

3. 通过函数式绑定

  • 使用 useTemplateRef('inputEl') 替代字符串命名,消除变量名冲突导致的无效渲染

4. SSR 兼容性优化

  • useTemplateRef 在 SSR 环境下表现良好,无需额外处理,服务端渲染时也能正常工作

5. 条件渲染时及时释放引用

  • 条件渲染(如 v-if)下,元素销毁时 useTemplateRef 会自动置为 null无需手动清理,避免内存泄漏

6. 避免在循环中频繁创建 ref

  • 如需为列表项绑定 ref,建议使用 v-for 的回调 ref 或统一管理,避免为每个项单独调用 useTemplateRef,提升渲染性能

更多示例

v-for 循环中使用

<script setup>
import { ref, useTemplateRef, onMounted } from "vue";

const items = ref([
  { id: 1, name: "项目一", status: "进行中" },
  { id: 2, name: "项目二", status: "已完成" },
  { id: 3, name: "项目三", status: "计划中" },
]);

const itemRefs = useTemplateRef("listItems");

onMounted(() => {
  itemRefs.value.forEach((el, index) => {
    el.style.animationDelay = `${index * 0.5}s`;
  });
});
</script>

<template>
  <div
    class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 py-12 px-4"
  >
    <div class="max-w-2xl mx-auto">
      <div class="text-center mb-8">
        <h1 class="text-3xl font-bold text-gray-800 mb-2">项目列表</h1>
      </div>
      <div class="grid gap-6 md:grid-cols-2">
        <div
          v-for="item in items"
          :key="item.id"
          ref="listItems"
          class="bg-white rounded-xl shadow-md hover:shadow-lg transition-all duration-300 transform hover:-translate-y-1 border border-gray-100 animate-fade-in p-6 flex items-center justify-between"
        >
          <span class="text-lg font-medium text-gray-800">{{ item.name }}</span>
          <span
            :class="{
              'bg-green-100 text-green-800': item.status === '已完成',
              'bg-blue-100 text-blue-800': item.status === '进行中',
              'bg-yellow-100 text-yellow-800': item.status === '计划中',
            }"
            class="px-3 py-1 rounded-full text-xs font-medium"
          >
            {{ item.status }}
          </span>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
@keyframes fade-in {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.animate-fade-in {
  animation: fade-in 0.6s ease-out forwards;
}
</style>

表单验证

<script setup>
import { ref, useTemplateRef } from "vue";

const inputs = useTemplateRef("formInput");
const values = ref(["", "", ""]);

function validate() {
  inputs.value.forEach((el, idx) => {
    if (!values.value[idx]) {
      el.style.borderColor = "red";
    } else {
      el.style.borderColor = "";
    }
  });
}
</script>

<template>
  <div>
    <input
      v-for="(val, idx) in values"
      :key="idx"
      v-model="values[idx]"
      ref="formInput"
      placeholder="请输入内容"
      class="border p-2 m-2"
    />
    <button @click="validate" class="bg-blue-500 text-white px-4 py-2 rounded">
      校验
    </button>
  </div>
</template>

批量应用指令

<script setup>
import { ref, useTemplateRef, onMounted } from "vue";

const elements = useTemplateRef("customElement");
const items = ref([1, 2, 3]);

// 自定义指令逻辑
function applyCustomDirective(el) {
  el.style.backgroundColor = "#e5f3ff";
  el.style.border = "2px solid #3b82f6";
  el.style.borderRadius = "8px";
  el.style.padding = "12px";
  el.style.margin = "8px";
}

onMounted(() => {
  // 批量应用自定义指令
  elements.value.forEach((el, index) => {
    applyCustomDirective(el);
    el.textContent = `元素 ${index + 1}`;
  });
});
</script>

<template>
  <div>
    <div
      v-for="item in items"
      :key="item"
      ref="customElement"
      class="bg-gray-100 p-4 m-2 rounded"
    >
      原始内容
    </div>
  </div>
</template>

最佳实践

  1. 明确类型: useTemplateRef<HTMLInputElement>()
  2. 空值检查: 使用可选链操作符
  3. 生命周期: 在 onMounted 后安全访问
资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/954,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?