Vue3 入门学习
Vue3 技术文章大纲
Vue3 核心特性与优势
Composition API 的设计理念与优势
Composition API 是 Vue3 的核心特性之一,旨在解决 Options API 在复杂组件中逻辑分散的问题。通过 setup 函数,可以将相关逻辑组织在一起,提高代码的可读性和可维护性。Composition API 支持逻辑复用,通过自定义 Hook 实现跨组件逻辑共享,避免 Mixins 的命名冲突和来源不清晰问题。
性能优化
Vue3 在性能方面进行了显著优化。使用 Proxy 替代 Object.defineProperty 实现响应式系统,支持动态属性添加和数组索引修改,性能更高。Tree-shaking 支持使得打包体积更小,未使用的功能不会包含在最终构建中。虚拟 DOM 重写,优化了 diff 算法,提升了渲染性能。
更好的 TypeScript 集成
Vue3 从底层开始使用 TypeScript 重写,提供了更好的类型推断和支持。Composition API 的设计使得 TypeScript 集成更加自然,类型推导更加准确。开发者可以享受到完整的类型检查和代码提示,提升开发体验和代码质量。
新特性
- 片段(Fragment):支持组件返回多个根节点,无需包裹额外的 DOM 元素。
- Teleport:允许将子组件渲染到 DOM 中的其他位置,适用于模态框、通知等场景。
- Suspense:提供异步组件加载的解决方案,支持加载状态和错误处理。
- 自定义渲染器:支持自定义渲染逻辑,适用于非 DOM 环境(如小程序、Canvas)。
环境搭建与项目初始化
确保系统已安装 Node.js(建议版本 16+)。通过以下命令检查版本:
node -v
npm -v
全局安装或升级 Vite:
npm install -g create-vite
使用 Vite 创建 Vue3 项目
执行创建命令并选择模板:
npm create vite@latest my-vue-app --template vue
进入项目目录并安装依赖:
cd my-vue-app
npm install
启动开发服务器:
npm run dev
Vue CLI 与 Vite 的对比
构建工具差异
Vue CLI 基于 Webpack,内置完整的配置和插件体系;Vite 采用原生 ES Modules,利用浏览器直接加载模块,开发环境下无需打包。
启动速度
Vite 冷启动时间极短,依赖预构建和按需编译;Vue CLI 在大型项目中启动较慢,需等待完整打包。
生产构建
Vite 使用 Rollup 进行生产构建,输出高度优化的静态资源;Vue CLI 依赖 Webpack 的复杂配置,但插件生态更成熟。
配置复杂度
Vite 配置更简洁,默认支持 TypeScript 和 CSS 预处理器;Vue CLI 提供图形化界面,但自定义配置需熟悉 Webpack。
基础项目结构解析
典型 Vite + Vue3 项目结构:
my-vue-app/
├── node_modules/ # 依赖库
├── public/ # 静态资源(不经过构建)
├── src/
│ ├── assets/ # 编译处理的静态资源
│ ├── components/ # 公共组件
│ ├── App.vue # 根组件
│ └── main.js # 应用入口文件
├── vite.config.js # Vite 配置文件
├── package.json # 项目元数据和脚本
└── index.html # 入口 HTML 文件
关键文件说明:
vite.config.js:可配置代理、插件、别名等,支持热更新。index.html:Vite 将自动注入模块脚本,无需手动引入。main.js:使用createApp初始化 Vue 实例,支持 Composition API。
Composition API 详解
ref 与 reactive 的使用场景与区别
ref 和 reactive 是 Vue 3 Composition API 中用于创建响应式数据的两种主要方式。
-
ref
适用于基本类型(如string、number、boolean)或需要直接引用的对象。ref通过.value访问或修改其值,但在模板中会自动解包,无需使用.value。
示例代码:const count = ref(0); count.value++; // 修改值 -
reactive
适用于对象或数组等复杂数据结构。reactive直接返回一个响应式代理对象,无需.value访问。
示例代码:const state = reactive({ count: 0 }); state.count++; // 直接修改属性
区别
ref可以包装任何值,而reactive仅接受对象/数组。ref通过.value操作数据,reactive直接操作属性。- 在组合函数中返回响应式数据时,通常使用
ref以保证解构后仍保持响应性。
computed 与 watch 的进阶用法
-
computed
用于派生依赖其他响应式数据的计算属性,具有缓存机制。
进阶用法:传入get和set函数实现可写计算属性。
示例代码:const fullName = computed({ get() { return `${firstName.value} ${lastName.value}`; }, set(newValue) { [firstName.value, lastName.value] = newValue.split(' '); } }); -
watch
监听响应式数据的变化,支持深度监听和立即执行。
进阶用法:- 使用
watchEffect自动追踪依赖,无需显式指定监听源。 - 通过
{ deep: true }监听嵌套对象变化。
示例代码:
watchEffect(() => console.log(count.value)); // 自动追踪 count watch( () => state.count, (newVal, oldVal) => { /* 逻辑 */ }, { deep: true } ); - 使用
生命周期钩子在 Composition API 中的使用
Composition API 提供了与 Options API 对应的生命周期钩子函数,均需在 setup() 中调用:
onMounted:组件挂载完成后执行。onUpdated:响应式数据变更导致 DOM 更新后执行。onUnmounted:组件卸载后执行。onBeforeMount/onBeforeUpdate/onBeforeUnmount等。
示例代码:
import { onMounted } from 'vue';
setup() {
onMounted(() => {
console.log('组件已挂载');
});
}
自定义 Hooks 的封装与实践
自定义 Hooks 是通过组合 Composition API 的函数实现逻辑复用的模式,类似于 React Hooks。
封装步骤
- 将可复用的逻辑提取为函数,函数名通常以
use开头。 - 在函数内部使用
ref、reactive、computed等响应式 API。 - 返回需要暴露的响应式数据或方法。
示例:封装鼠标位置跟踪 Hook
// useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue';
export function useMousePosition() {
const x = ref(0);
const y = ref(0);
const update = (e) => {
x.value = e.pageX;
y.value = e.pageY;
};
onMounted(() => window.addEventListener('mousemove', update));
onUnmounted(() => window.removeEventListener('mousemove', update));
return { x, y };
}
使用示例
import { useMousePosition } from './useMousePosition';
setup() {
const { x, y } = useMousePosition();
return { x, y };
}
优势
- 逻辑高内聚、低耦合,易于跨组件复用。
- 避免 Options API 中
mixins的命名冲突问题。
Proxy 与 Reflect 的底层实现
Proxy 是 ES6 引入的元编程特性,用于创建对象的代理,拦截并自定义基本操作(如属性访问、赋值等)。Reflect 提供了一组与 Proxy 拦截器对应的方法,用于简化操作。
const target = { foo: 'bar' };
const handler = {
get(target, key, receiver) {
console.log(`Get ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`Set ${key} to ${value}`);
return Reflect.set(target, key, value, receiver);
}
};
const proxy = new Proxy(target, handler);
proxy.foo; // 输出 "Get foo"
proxy.foo = 'baz'; // 输出 "Set foo to baz"
依赖收集与触发更新的机制
依赖收集通过拦截属性的读取操作(get)实现,将当前执行的副作用函数(effect)存储到依赖集合中。触发更新通过拦截属性的设置操作(set)实现,通知所有关联的副作用函数重新执行。
const depsMap = new Map();
let activeEffect;
function track(target, key) {
if (!activeEffect) return;
let dep = depsMap.get(target);
if (!dep) {
dep = new Map();
depsMap.set(target, dep);
}
let effects = dep.get(key);
if (!effects) {
effects = new Set();
dep.set(key, effects);
}
effects.add(activeEffect);
}
function trigger(target, key) {
const dep = depsMap.get(target);
if (!dep) return;
const effects = dep.get(key);
effects && effects.forEach(effect => effect());
}
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
手动控制响应式的进阶 API
shallowRef
创建一个浅层响应式引用,仅对 .value 的直接变更触发更新,内部属性变更不会触发。
function shallowRef(value) {
return {
get value() {
track(this, 'value');
return value;
},
set value(newVal) {
if (Object.is(value, newVal)) return;
value = newVal;
trigger(this, 'value');
}
};
}
markRaw
标记对象为“原始”数据,跳过 Proxy 代理,避免其被转换为响应式对象。
const rawSet = new WeakSet();
function markRaw(obj) {
rawSet.add(obj);
return obj;
}
function reactive(obj) {
if (rawSet.has(obj)) return obj;
return new Proxy(obj, { /* 拦截器 */ });
}
单文件组件(SFC)的语法更新
Vue 3 的单文件组件语法进行了多项改进,支持更简洁的 <script setup> 语法糖。通过 defineProps 和 defineEmits 可以在 <script setup> 中直接声明 props 和 emits,无需显式导入。
<script setup lang="ts">
const props = defineProps<{
title: string;
count?: number;
}>();
const emit = defineEmits<{
(e: 'update', value: string): void;
}>();
</script>
defineProps 与 defineEmits 的 TypeScript 支持
在 TypeScript 中,defineProps 和 defineEmits 支持泛型或运行时声明两种方式。泛型方式提供完整的类型推断,无需额外类型标注。
// 泛型方式
defineProps<{ msg: string }>();
// 运行时声明(兼容性更好)
defineProps({
msg: { type: String, required: true }
});
插槽(Slots)与作用域插槽的用法
Vue 3 的插槽语法与作用域插槽统一为 v-slot 或简写 #。作用域插槽通过插槽 props 传递数据。
<!-- 默认插槽 -->
<template #default="{ user }">
{{ user.name }}
</template>
<!-- 具名插槽 -->
<template #header>
<h1>Header</h1>
</template>
动态组件与异步组件的优化
动态组件通过 <component :is> 实现,结合 defineAsyncComponent 可优化异步组件加载,支持懒加载和错误处理。
import { defineAsyncComponent } from 'vue';
const AsyncComp = defineAsyncComponent({
loader: () => import('./Component.vue'),
loadingComponent: LoadingSpinner,
delay: 200,
timeout: 3000
});
性能优化建议
- 使用
v-once或v-memo减少静态内容渲染开销。 - 通过
markRaw标记非响应式对象以避免不必要的代理。 - 异步组件结合
Suspense实现更流畅的加载体验。
Pinia 核心概念
Pinia 是 Vue 的轻量级状态管理库,基于 Composition API 设计,核心概念包括:
- Store:通过
defineStore定义的状态单元,支持多模块。 - State:使用
ref或reactive定义响应式数据。 - Getters:通过
computed实现派生状态。 - Actions:同步或异步方法,直接修改
state。
状态模块化实践
每个功能模块独立为 Store 文件,通过组合式函数按需引入:
// stores/user.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({ name: '', age: 0 }),
actions: {
async fetchUser() { /* API 请求 */ }
}
});
在组件中按需调用:
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
持久化策略
通过插件(如 pinia-plugin-persistedstate)实现状态持久化:
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
在 Store 中配置:
defineStore('user', {
persist: {
key: 'user-data',
storage: localStorage,
paths: ['name'] // 仅持久化 name 字段
}
});
与 Composition API 集成
直接结合 setup() 使用,避免 mapState 等辅助函数:
import { storeToRefs } from 'pinia';
const userStore = useUserStore();
const { name, age } = storeToRefs(userStore); // 解构保持响应性
const updateName = () => userStore.name = 'New Name';
对比 Vuex 的优势
- 类型支持:天然支持 TypeScript,无需额外配置。
- 简洁 API:去除
mutations,直接通过actions修改状态。 - 模块化:无需嵌套模块,每个 Store 独立注册。
- 体积更小:压缩后约 1KB,适合轻量级应用。
性能优化建议
- 避免在 Store 中存储非响应式数据(如静态配置)。
- 使用
storeToRefs解构 Store 属性,防止响应式丢失。 - 对高频更新的状态使用
shallowRef减少深层响应开销。
Vue Router 4.x 新特性解析
路由守卫与组合式 API 结合
Vue Router 4.x 支持在 setup() 中使用路由守卫,通过 onBeforeRouteLeave 和 onBeforeRouteUpdate 等组合式函数实现。例如:
import { onBeforeRouteLeave } from 'vue-router'
export default {
setup() {
onBeforeRouteLeave((to, from) => {
return confirm('确定离开当前页面?')
})
}
}
这种方式替代了传统的 beforeRouteLeave 选项式 API,使逻辑更集中。
动态路由改进
动态路由匹配通过 :param 语法实现,可通过 useRoute() 获取参数:
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id) // 动态参数
新增的 path-to-regexp 解析引擎支持更灵活的路由匹配规则。
懒加载优化
路由组件支持 defineAsyncComponent 实现懒加载:
const UserDetails = () => import('./views/UserDetails.vue')
或结合 Suspense 使用:
const router = createRouter({
routes: [
{
path: '/user',
component: defineAsyncComponent(() => import('./User.vue'))
}
]
})
Webpack 的魔法注释可进一步优化分包:
const User = () => import(/* webpackChunkName: "user" */ './User.vue')
导航守卫类型强化
通过 TypeScript 泛型增强类型推断:
router.beforeEach((to): boolean | NavigationGuardReturn => {
if (to.meta.requiresAuth) return '/login'
})
组合式 API 的守卫函数也支持完整的类型提示。
路由优先级规则
动态路由可通过 priority 属性调整匹配顺序:
const routes = [
{ path: '/user/:id', priority: 10 },
{ path: '/user/create', priority: 20 } // 更高优先级
]
滚动行为改进
scrollBehavior 支持返回 Promise:
const router = createRouter({
scrollBehavior(to) {
return new Promise(resolve => {
setTimeout(() => resolve({ top: 0 }), 500)
})
}
})
工程化与性能优化:基于 Vite 的构建配置
代码分割与预加载策略
Vite 默认使用 Rollup 进行代码分割,通过动态导入(import())自动分割代码块。优化策略包括手动配置 rollupOptions 控制分割逻辑:
// vite.config.js
export default {
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
if (id.includes('node_modules')) {
return 'vendor'
}
if (id.includes('src/components')) {
return 'components'
}
}
}
}
}
}
预加载通过 <link rel="modulepreload"> 自动注入,可通过 build.polyfillModulePreload 禁用或自定义。
自定义指令与全局属性管理
全局指令通过 app.directive 注册:
// main.js
import { createApp } from 'vue'
const app = createApp(App)
app.directive('focus', {
mounted(el) {
el.focus()
}
})
全局属性(如 $filters)可通过 app.config.globalProperties 挂载:
app.config.globalProperties.$filters = {
currency(value) {
return '$' + value
}
}
构建性能优化
- 依赖预构建:Vite 自动预构建
node_modules,通过optimizeDeps手动配置:
// vite.config.js
export default {
optimizeDeps: {
include: ['lodash-es']
}
}
- 缓存策略:默认缓存目录
node_modules/.vite,可通过cacheDir修改路径。 - 多线程编译:启用
build.minify时,Vite 默认使用 Terser 多线程压缩。
开发环境优化
- 热更新(HMR):Vite 提供开箱即用的 HMR,对 Vue/Svelte 等框架有深度集成。
- 按需编译:浏览器仅请求当前路由所需的模块,通过
server.open配置自动打开页面。
生产环境优化
- CSS 代码分割:
build.cssCodeSplit默认为true,分离 CSS 文件减少主包体积。 - 异步 chunk 加载:通过
build.assetsInlineLimit控制小资源是否内联为 Base64。 - Bundle 分析:使用
rollup-plugin-visualizer生成构建报告:
import { visualizer } from 'rollup-plugin-visualizer'
export default {
plugins: [visualizer()]
}
Vitest + Vue Test Utils 组件测试实践案例
安装依赖 确保项目中已安装 vitest、@vue/test-utils 和 jsdom(用于模拟浏览器环境)。通过以下命令安装:
npm install -D vitest @vue/test-utils jsdom
配置 Vitest 在 vite.config.js 或单独配置文件中添加 Vitest 配置:
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
globals: true,
},
});
编写组件测试 以测试一个简单的 Button.vue 组件为例:
import { mount } from '@vue/test-utils';
import Button from './Button.vue';
describe('Button.vue', () => {
it('renders button text correctly', () => {
const wrapper = mount(Button, {
props: { label: 'Click Me' },
});
expect(wrapper.text()).toContain('Click Me');
});
it('emits click event', async () => {
const wrapper = mount(Button);
await wrapper.trigger('click');
expect(wrapper.emitted()).toHaveProperty('click');
});
});
模拟用户交互 使用 trigger 方法模拟用户操作,如点击、输入等:
it('updates input value', async () => {
const wrapper = mount(MyInput);
await wrapper.find('input').setValue('Hello');
expect(wrapper.vm.value).toBe('Hello');
});
Chrome DevTools 的 Vue3 调试技巧
启用 Vue DevTools 确保已安装 Vue DevTools 浏览器扩展。在 Chrome 中打开开发者工具(F12 或 Ctrl+Shift+I),切换到 Vue 选项卡。
组件树检查 在 Vue DevTools 中查看组件层级结构,选中组件后可实时查看其 props、data、computed 等属性。
状态调试 直接修改组件的 data 或 props 值,观察界面实时响应。适用于动态调试数据流。
事件追踪 在 Events 选项卡中查看组件触发的事件及其载荷,帮助定位事件传递问题。
性能分析 使用 Timeline 功能记录组件渲染和更新的性能,识别渲染瓶颈。
源码映射调试 确保 vite.config.js 中已启用源码映射(sourcemap: true),以便在 DevTools 中直接调试原始 Vue 文件而非编译后代码。
自定义指令调试 在 Vue DevTools 中检查自定义指令的绑定值和生命周期钩子调用情况。
项目初始化与基础配置
使用 Vue CLI 或 Vite 创建一个新的 Vue 3 项目。安装必要依赖:
npm create vue@latest todolist
cd todolist
npm install axios element-plus
在 main.js 中集成 Element Plus:
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
Axios 封装与 API 管理
创建 src/utils/request.js 封装基础请求:
import axios from 'axios'
const service = axios.create({
baseURL: 'https://your-api-domain.com/api',
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(config => {
config.headers.Authorization = localStorage.getItem('token') || ''
return config
})
// 响应拦截器
service.interceptors.response.use(
response => response.data,
error => {
console.error('API Error:', error.response?.data)
return Promise.reject(error)
}
)
export default service
创建 src/api/todo.js 管理具体接口:
import request from '../utils/request'
export const getTodoList = () => request.get('/todos')
export const addTodo = (data) => request.post('/todos', data)
export const updateTodo = (id, data) => request.patch(`/todos/${id}`, data)
export const deleteTodo = (id) => request.delete(`/todos/${id}`)
组件开发与状态管理
创建 src/components/TodoList.vue:
<template>
<div class="todo-container">
<el-input
v-model="newTodo"
placeholder="输入任务内容"
@keyup.enter="handleAdd"
>
<template #append>
<el-button @click="handleAdd">添加</el-button>
</template>
</el-input>
<el-table :data="todoList" style="width: 100%">
<el-table-column prop="content" label="任务内容" />
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button size="small" @click="handleComplete(row)">完成</el-button>
<el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getTodoList, addTodo, updateTodo, deleteTodo } from '../api/todo'
const todoList = ref([])
const newTodo = ref('')
const fetchTodos = async () => {
try {
const res = await getTodoList()
todoList.value = res.data
} catch (error) {
console.error('获取列表失败:', error)
}
}
const handleAdd = async () => {
if (!newTodo.value.trim()) return
try {
await addTodo({ content: newTodo.value })
newTodo.value = ''
fetchTodos()
} catch (error) {
console.error('添加失败:', error)
}
}
const handleComplete = async (todo) => {
try {
await updateTodo(todo.id, { completed: !todo.completed })
fetchTodos()
} catch (error) {
console.error('更新失败:', error)
}
}
const handleDelete = async (id) => {
try {
await deleteTodo(id)
fetchTodos()
} catch (error) {
console.error('删除失败:', error)
}
}
onMounted(fetchTodos)
</script>
服务端模拟(JSON Server)
安装 JSON Server 用于快速模拟 API:
npm install -g json-server
创建 db.json 文件:
{
"todos": [
{ "id": 1, "content": "学习 Vue 3", "completed": false },
{ "id": 2, "content": "封装 Axios", "completed": true }
]
}
启动模拟服务器:
json-server --watch db.json --port 3000
修改 request.js 中的 baseURL 为 http://localhost:3000
错误处理优化
在 request.js 中增强错误处理:
service.interceptors.response.use(
response => {
if (response.data.code !== 200) {
return Promise.reject(new Error(response.data.message || 'Error'))
}
return response.data
},
error => {
const message = error.response?.data?.message || error.message
ElMessage.error(message)
return Promise.reject(error)
}
)
样式优化与功能扩展
添加加载状态和空状态提示:
<template>
<el-table
v-loading="loading"
:data="todoList"
style="width: 100%"
>
<!-- ...原有列定义... -->
<template #empty>
<el-empty description="暂无任务" />
</template>
</el-table>
</template>
<script setup>
const loading = ref(false)
const fetchTodos = async () => {
loading.value = true
try {
const res = await getTodoList()
todoList.value = res.data
} finally {
loading.value = false
}
}
</script>
添加过滤功能:
<el-radio-group v-model="filterStatus">
<el-radio-button label="all">全部</el-radio-button>
<el-radio-button label="active">未完成</el-radio-button>
<el-radio-button label="completed">已完成</el-radio-button>
</el-radio-group>
<script setup>
const filterStatus = ref('all')
const filteredTodos = computed(() => {
switch (filterStatus.value) {
case 'active':
return todoList.value.filter(todo => !todo.completed)
case 'completed':
return todoList.value.filter(todo => todo.completed)
default:
return todoList.value
}
})
</script>
SSR 方案(Nuxt.js 3)
Nuxt.js 3 基于 Vue 3 提供了开箱即用的 SSR 支持,通过混合渲染模式(Hybrid Rendering)实现动态与静态内容的结合。关键配置在 nuxt.config.ts 中定义路由规则,使用 defineNuxtConfig 指定渲染模式:
export default defineNuxtConfig({
routeRules: {
'/static': { static: true }, // 纯静态生成
'/dynamic': { ssr: true }, // 服务端渲染
'/spa': { ssr: false } // 客户端渲染
}
})
数据获取通过 useAsyncData 或 useFetch 在组件内完成,服务端会自动处理异步数据预取。对于组件级缓存,可通过 server/components 目录配置组件级别的缓存策略。
微前端架构中的 Vue3 实践
基于 Module Federation 的微前端方案适用于 Vue 3。通过 Webpack 5 的模块联邦特性,主应用动态加载子应用:
// 主应用配置
new ModuleFederationPlugin({
remotes: {
vue3SubApp: 'vue3SubApp@http://localhost:3001/remoteEntry.js'
}
})
子应用需暴露 Vue 组件:
// 子应用配置
exposes: {
'./Button': './src/components/Button.vue'
}
样式隔离可通过 Shadow DOM 或 CSS 命名空间实现。状态管理推荐使用 Pinia 的跨实例共享方案,通过主应用注入 store 上下文。
Vue3 与 Web Components 的协作
Vue 3 支持将组件编译为原生 Web Components:
import { defineCustomElement } from 'vue'
import MyVueComponent from './MyComponent.vue'
const MyElement = defineCustomElement(MyVueComponent)
customElements.define('my-element', MyElement)
属性传递通过 props 映射,事件通过 CustomEvent 派发。在 Nuxt 3 中需在 nuxt.config.ts 配置构建选项:
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: tag => tag.includes('-')
}
}
})
性能优化需注意 Shadow DOM 的样式封装特性,避免重复加载 Vue 运行时。可通过 @vue/web-component-wrapper 实现更复杂的生命周期控制。
响应式数据丢失的排查方法
检查数据绑定的语法是否正确,确保使用了正确的指令(如 v-model 或 v-bind)。
验证数据是否在组件的 data 或 setup 函数中正确定义,避免直接修改未声明的属性。
使用 Vue Devtools 检查数据流,确认数据是否被意外覆盖或未触发更新。
排查异步操作(如 API 调用)是否未正确处理响应式数据的更新,必要时使用 Vue.set 或 this.$set 强制更新。
性能瓶颈的分析工具
使用 Chrome DevTools 的 Performance 面板录制页面运行过程,分析脚本执行时间和内存占用。
通过 Vue Devtools 的 Performance 选项卡检测组件渲染时间,定位重复渲染或低效的组件。
借助 Lighthouse 生成性能报告,获取加载速度、资源优化等具体建议。
对于复杂计算逻辑,使用 console.time 和 console.timeEnd 测量函数执行耗时。
版本迁移的注意事项
对比新旧版本的官方迁移指南,重点关注破坏性变更(如 API 弃用或语法调整)。
逐步升级依赖库,优先解决兼容性冲突,避免一次性全局升级导致问题难以定位。
在测试环境中验证核心功能,确保路由、状态管理等关键模块行为符合预期。
备份项目代码并启用版本控制,便于回滚到稳定版本。
更多推荐
所有评论(0)