10 个 Vue 3 性能飙升技巧
技巧 #1:用 shallowreactive 代替 reactive —— 节能模式
import { shallowReactive } from"vue";
// 使用 shallowReactive 创建一个仅顶层属性为响应式的对象
const userInfo = shallowReactive({
name: "前端专家",
address: { city: "", street: "" }, // 嵌套对象
hobbies: ["编程", "调试"],
});
// ✅ 顶层属性的变更会触发更新
userInfo.name = "Vue 高手";
// ❌ 嵌套对象属性的变更不会触发更新,从而避免了不必要的渲染
userInfo.address.city = "旧金山";
技巧 #2:使用 toRefs 实现 Ref 解构魔法
import { reactive, toRefs } from "vue";
// 创建一个响应式对象
const user = reactive({ name: "Jane", age: 30 });
// 使用 toRefs 将对象的属性解构为独立的 ref
const { name, age } = toRefs(user);
// ✅ 现在可以像 ref 一样直接修改值,并触发响应式更新
name.value = "Doe";
技巧 #3:使用 watchEffect 进行智能侦听
import { ref, watchEffect } from "vue";
const count = ref(0);
const double = ref(0);
// watchEffect 会立即执行一次,然后自动追踪其内部用到的响应式依赖(这里是 `count`)
watchEffect(() => {
// 当 count 的值变化时,这个函数会自动重新执行
double.value = count.value * 2;
});
// 增加 count 的值,上面的 watchEffect 回调将会被触发
count.value++;
技巧 #4:Suspense —— 让异步加载如丝般顺滑
<template>
<Suspense>
<!-- #default 插槽:当异步组件加载完成时显示 -->
<template #default>
<AsyncComponent />
</template>
<!-- #fallback 插槽:在异步组件加载期间显示的“加载中”UI -->
<template #fallback>
<p>全力加载中...</p>
</template>
</Suspense>
</template>
<script setup>
import { defineAsyncComponent } from "vue";
// 使用 defineAsyncComponent 定义一个异步组件
const AsyncComponent = defineAsyncComponent(() => import("./AsyncComponent.vue"));
</script>
技巧 #5:Teleport —— 随心所欲地渲染!
<template>
<button @click="show = true">打开模态框</button>
<!-- 使用 Teleport 将内部内容传送到 body 标签下 -->
<Teleport to="body">
<p
v-if="show"
class="modal"
>
<!-- 这个 p 会被渲染在 <body> 的直接子节点中 -->
这是一个模态框
<button @click="show = false">关闭</button>
</p>
</Teleport>
</template>
技巧 #6:v-copy 指令 —— 一键复制
// 在 main.js 或插件文件中定义一个全局自定义指令
app.directive("copy", {
// 当指令绑定到元素上时触发
mounted(el, binding) {
el.addEventListener("click", () => {
// 创建一个临时的 textarea 用于执行复制操作
const textarea = document.createElement("textarea");
// binding.value 是指令绑定的值,即 'Text to copy'
textarea.value = binding.value;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
// 操作完成后移除临时元素
document.body.removeChild(textarea);
alert("已复制!");
});
},
});
<!-- 在组件中直接使用指令 -->
<button v-copy="'需要复制的文本'">点我复制</button>
技巧 #7:Pinia 插件 —— 为状态管理增添超能力
// 插件:为所有 store 添加一个 $reset 方法
const resetPlugin = ({ store }) => {
// $initialState 是我们自定义添加的属性,用于存储初始状态
const initialState = JSON.parse(JSON.stringify(store.$state));
store.$reset = () => store.$patch(initialState);
};
// 创建 Pinia 实例并使用插件
const pinia = createPinia();
pinia.use(resetPlugin);
// 在组件中使用
const userStore = useUserStore();
userStore.$reset(); // 调用插件添加的自定义方法!
技巧 #8:v-memo —— 为列表渲染涡轮增压
<ul>
<li
v-for="item in items"
:key="item.id"
<!-- v-memo 接收一个依赖数组 -->
<!-- 只有当 item.id 或 item.status 变化时,这个 li 才会重新渲染 -->
v-memo="[item.id, item.status]"
>
{{ item.name }} - {{ item.status }}
</li>
</ul>
技巧 #9:useIntersectionObserver —— 智能懒加载
<script setup>
import { ref } from'vue';
import { useIntersectionObserver } from'@vueuse/core';
// 创建一个 ref 来引用目标元素
const target = ref(null);
// 一个 ref 用于追踪元素是否可见
const isVisible = ref(false);
// 设置 Intersection Observer
useIntersectionObserver(
target, // 监听的目标元素
([{ isIntersecting }]) => {
// 当元素进入视口时,isIntersecting 会变为 true
if (isIntersecting) {
isVisible.value = true;
}
},
);
</script>
<template>
<img
ref="target"
<!-- 仅当元素可见时才设置 src 属性,从而实现懒加载 -->
:src="isVisible ? 'real-image-url.jpg' : 'placeholder.png'"
alt="懒加载图片"
>
</template>
技巧 #10:自定义 Hooks (Composables) —— 终极复用性
// composables/useFormValidation.js
import { ref } from"vue";
exportdefaultfunction useFormValidation() {
// 封装表单数据和错误状态
const email = ref("");
const errors = ref({});
// 封装验证逻辑
const validate = () => {
errors.value = {};
if (!email.value) {
errors.value.email = "此项为必填项";
} elseif (!email.value.includes("@")) {
errors.value.email = "请输入有效的邮箱地址";
}
// 如果错误对象没有属性,则验证通过
returnObject.keys(errors.value).length === 0;
};
// 返回响应式状态和方法
return { email, errors, validate };
}
<!-- 在组件中使用 -->
<script setup>
import useFormValidation from "./composables/useFormValidation";
// 像使用普通 Hook 一样调用,获取所需的状态和方法
const { email, errors, validate } = useFormValidation();
</script>
<template>
<input
v-model="email"
@blur="validate"
/>
<p v-if="errors.email">{{ errors.email }}</p>
</template>
来自:https://mp.weixin.qq.com/s/ql0REKVPAl2l9yI-wNiXJA
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!