注意:
仅适用于异步组件(即用 defineAsyncComponent 或 () => import(...) 定义的组件)。
5. 使用 <Teleport> 解决模态框层级问题
问题:
弹窗写在组件内部,可能被父级的 overflow: hidden 或 z-index 限制,导致显示不全或盖不住其他内容。
解决方案:
用 <Teleport> 把组件“传送”到 <body> 底部,脱离当前 DOM 树。
示例:
<Teleport to="body">
<Modal v-if="show" />
</Teleport>
app.directive('copy', {
mounted(el, binding) {
el.addEventListener('click', () => {
navigator.clipboard.writeText(binding.value);
});
}
});
<button v-copy="'要复制的内容'">点我复制</button>
好处:逻辑集中、复用性强、模板干净。
7. 用 Pinia 插件扩展 store 能力
问题:
每个 store 都想加个“重置”功能?手动一个个写太重复。
解决方案:
通过 Pinia 插件,一次性给所有 store 添加 $reset() 方法。
正确实现:
pinia.use(({ store }) => {
// 保存初始状态快照(深拷贝)
const initialState = JSON.parse(JSON.stringify(store.$state));
store.$reset = () => {
store.$state = initialState;
};
});
使用:
const userStore = useUserStore();
userStore.$reset(); // 恢复初始状态
适用场景:表单重置、清除缓存、统一日志等。
注意:不能直接用 store.$patch(store.$state),因为 $state 是当前状态,不是初始状态!
8. v-memo 优化大型列表渲染
问题:
列表有上千项,哪怕只改了一行的状态,Vue 默认会重新比对整张表,浪费性能。
解决方案:
用 v-memo 告诉 Vue:“只有这些值变了,才需要重新渲染这一行”。
示例:
<li v-for="item in list" :key="item.id" v-memo="[item.id, item.status]">
{{ item.name }} —— 状态:{{ item.status }}
</li>
注意事项:
- 适合内容稳定、更新频率低的大列表。
- 不要和
<transition-group> 一起用(会失效)。
- 高频变动的列表慎用,可能适得其反。
v-memo 是 Vue 3.2+ 的功能。
9. 虚拟滚动(Virtual Scrolling)
问题:
渲染 10,000 条消息?浏览器直接卡死!
解决方案:
只渲染“当前可见区域”的内容,滑动时动态替换,内存和性能都省下来。
推荐库(Vue 3 兼容):
vueuc(轻量、活跃维护)
vue-virtual-scroll-grid
安装 & 示例(以 vueuc 为例):
<script setup>
import { VirtualList } from 'vueuc';
</script>
<template>
<VirtualList :items="messages" :item-height="60" :bench="10">
<template #default="{ item }">
<MessageItem :msg="item" />
</template>
</VirtualList>
</template>
{ path: '/about', component: () => import('./views/About.vue') }