Vue进阶

一、keep-alive

1.核心作用和使用场景

1.作用
  • 缓存组件实例:避免重复销毁和创建,保留组件状态(如DOM结构、响应式数据、事件监听
  • 提升性能:适用于需要频繁切换但状态需保留的组件(如Tab页、表单填写页
2.使用方式
 1<template>
 2  <keep-alive :include="['ComponentA', 'ComponentB']" :max="5">
 3    <component :is="currentComponent"></component>
 4  </keep-alive>
 5</template>

2.生命周期钩子变化

  • 新增钩子(仅在被缓存的组件中触发)
    • onActivated:组件被激活(插入DOM)时触发。
    • onDeactivated:组件被停用(移除DOM)时触发
  • 执行顺序:
    • 首次加载onCreate->onMounted->onActivated
    • 切换离开onDeactivated
    • 再次进入onActivated
    • 彻底销毁onUnmounted

3.关键配置属性

1.include
  • 匹配组件名称(name选项),仅缓存匹配的组件
  • 支持字符串、正则、数组
 1<!-- 缓存以 "Test" 开头的组件 -->
 2<keep-alive :include="/^Test/">  
 3
2.exclude
  • 排除指定组件,优先级高于include
3.max
  • 最大缓存实例数,超出时按LRU(最近最少使用)策略淘汰旧实例
  • LUR原理:有限淘汰最久未访问的实例

4.高频面试题

1.keep-alive实现原理
  • 缓存机制:通过Map或Object缓存组件vnode实例,渲染时直接从缓存中取
  • DOM处理
    1. 该组件实例对应的整个 DOM 树会被从真实的文档流 (DOM tree) 中完全移除 (detached) 。这就是为什么在页面检查器里看不到它的 DOM 了。
    2. 当这个组件再次被激活时,keep-alive 会从缓存中找到这个实例,直接复用这个组件实例(保留所有状态),并将它对应的 DOM 树重新插入 (attached) 到文档流中
2.如何动态控制组件缓存
  • 方案1:绑定动态include/exclude(响应式变量)
 1<keep-alive :include="cachedComponents">
  • 方案2:通过key强制重新渲染(改变key会销毁旧实例)
 1<component :is="currentComponent" :key="componentKey">
3.keep-alive如何结合路由使用
  • 搭配router-view
 1<router-view v-slot="{ Component }">
 2  <keep-alive>
 3    <component :is="Component" v-if="$route.meta.keepAlive" />
 4  </keep-alive>
 5  <component :is="Component" v-if="!$route.meta.keepAlive" />
 6</router-view>
  • 路由配置:通过meta字段标记需缓存的页面
 1{ path: '/home', component: Home, meta: { keepAlive: true } }
4.缓存组件如何更新数据
  • onActivated中刷新数据
 1onActivated(() => {
 2  fetchData(); 
 3});
5.max属性的作用及淘汰策略
  • 作用:避免内存无限增长,限制最大缓存实例
  • 淘汰策略:LRU(最近最少使用),优先移除最久未被访问的实例

5.注意事项

  1. 组件必须设置name选项:否则include/exclude无法匹配
  2. 避免内存泄漏:及时清理不需要缓存的组件(如通过max或动态include)
  3. SSR不兼容:keep-alive仅在客户端渲染中生效
  4. 缓存组件的状态保留:表单内容等会被保留,需手动重置或通过key强制更新

6.实战实例

 1<template>
 2  <button @click="toggleComponent">切换组件</button>
 3  <keep-alive :include="cachedComponents" :max="3">
 4    <component :is="currentComponent" :key="currentComponent" />
 5  </keep-alive>
 6</template>
 7
 8<script setup>
 9import { ref } from 'vue';
10import ComponentA from './ComponentA.vue';
11import ComponentB from './ComponentB.vue';
12
13const currentComponent = ref('ComponentA');
14const cachedComponents = ref(['ComponentA', 'ComponentB']);
15
16const toggleComponent = () => {
17  currentComponent.value = currentComponent.value === 'ComponentA' ? 'ComponentB' : 'ComponentA';
18};
19</script>

二、异步组件

1.核心概念与使用方式

1.定义异步组件
  • defineAsyncComponent函数(Vue3推荐方式)
 1import { defineAsyncComponent } from 'vue';
 2const AsyncCom = defineAsyncComponent(() => import('./MyComponent.vue'));
  • 动态import()语法(结合构建工具如Webpack/Vite实现代码分割)
 1const AsyncComp = defineAsyncComponent({
 2    loader: () => import('./MyComponent.vue'),
 3    loadingComponent: loadingSpinner,  
 4    errorComponent: ErrorDisplay,      
 5    delay: 1000,                       
 6    timeout,                           
 7})
2.Suspense组件
  • 统一管理异步组件(如异步组件或异步setup函数):
 1<template>
 2  <Suspense>
 3    <template #default>
 4      <AsyncComp />
 5    </template>
 6    <template #fallback>
 7      <div>Loading...</div>
 8    </template>
 9  </Suspense>
10</template>

2.高频面试题

1.异步组件的核心作用
  • 按需加载:减少初始包体积,提升首屏加载速度
  • 性能优化:结合代码分割(Code Spliting)动态加载非关键组件
2.如何配置异步组件的加载状态和错误处理?
  • loadingComponent:显示加载中的UI(如loading动画)
  • errorComponent:加载失败时显示错误提示
  • delay:延迟显示loading组件,避免快速加载时闪烁
  • timeout:超时后触发错误组件
3.Suspense和异步组件的关系
  • Suspense:内置组件,用于统一管理异步组件的加载状态(如多个异步组件并行加载)
  • 异步组件:通过defineAsyncComponent定义,由Suspense控制占位内容
4.如何实现组件加载失败后的重试逻辑
  • 工厂函数返回Promise:在loader中捕获错误并重试
 1const Async = defineAsyncComponent({
 2    loader: () => import('./MyComponent.vue')
 3        .catch(() => {
 4            
 5            return retryImport();
 6        })
 7})
5.异步组件在路由懒加载中的应用
  • Vue Router配置
 1const router = createRouter({
 2    route: [{
 3        path: '/profile',
 4        component: () => import('./Profile.vue'); 
 5        
 6        component: defineAsyncComponent(() => import('./Profile.vue')) 
 7    }]
 8})
6.Vue3异步组件与Vue2的差异
  • 语法差异:Vue3废弃Vue.component('async-comp',() => import(...)),改用defineAsyncComponent
  • 功能增强:Vue3支持更细颗粒度的加载状态管理和Suspense集成

3.底层原理优化

1.代码分割原理
  • 构建工具(如webpack)将动态import()的模块拆分为独立chunk,运行时按需加载
2.异步组件生命周期
  • 加载阶段:触发loader -> 下载loader -> 初始化组件
  • 缓存机制:已加载的组件实例会被缓存,避免重复加载
3.性能优化策略
  • 预加载(prefetch):通过Webpack魔法注释标记非关键资源
 1() => import( './MyComponent.vue')
  • 懒加载阈值:结合路由或用户行为预测延迟加载组件

4.注意事项

  1. 组件命名:异步组件需显式申明name选项,以便调试和keep-alive匹配
  2. SSR限制:异步组件在服务端渲染中需特殊处理(如占位内容)
  3. 错误边界:结合onErrorCaptured全局捕获异步组件错误
  4. 过度分割:避免过多小模块导致HTML请求激增

5.实战代码实例

 1const AsyncModal = defineAsyncComponent({
 2    lodaer: () => import('./Modal.vue').catch((err) ==> {
 3        console.log('加载失败,3s后重试...');
 4        return new Promise(resolve => {
 5            setTimeout(() => resolve(import('./Modal.vue')), 3000);
 6        })
 7    }),
 8    loadingComponent: LoadingSpainner,
 9    delay: 200,
10    timeout: 5000
11});
12
13export default {
14    setup() {
15        const showModal = ref(false);
16        return { showModal, AsyncModal };
17    }
18}

6.应用场景

  1. 大型应用模块懒加载:如管理后台的复杂表单/图表组件
  2. 条件渲染组件:用户交互后才加载的非必要组件(如弹窗)
  3. 路由级懒加载:结合Vue Router提升首屏性能

三、Vue-Router

1.Vue-Router 4.X核心变化

1.创建路由实例
 1import { createRouter, createWebHistory } from 'vue-router';
 2const router = createRouter({
 3    history: createWebHistory(),  
 4    routes: [...]
 5});
2.组合式API支持
  • useRouter():获取路由实例(替代this.$router
  • useRoute():获取当前路由对象(替代this.$route

2.路由配置与核心概念

1.动态路由
 1{ path: '/user/:id', component: User };
 2
2.嵌套路由
 1{
 2    path: '/parent',
 3    component: Parent,
 4    children: [
 5        { path: 'child', component: Child }
 6    ]
 7}
3.命名路由与编程式导航
 1router.push({ name: 'user', params: { id: 1 } });
4.路由模式
  • createWebHistory():History模式(需服务器支持)
  • createWebHashHistory():Hash模式
  • createMemoryHistory():SSR或测试环境
5.重定向与别名
 1{ path: '/home', redirect: '/' }
 2{ path: '/', alias: 'home' }

3.导航守卫

1.全局守卫
  • router.beforeEach((to, from, next) => { ... })
  • router.afterEach((to, from) => { ... })
  • router.beforeResolve()
2.路由独享守卫
 1{
 2    path: '/admin',
 3    component: Admin,
 4    beforeEnter: (to, from, next) => { ... }
 5}
3.组件内守卫
  • onBeforeRouteUpdate:路由参数变化
  • onBeforeRouteLeave:离开组件前
 1import { onBeforeRouteLeave } from 'vue-router';
 2export default {
 3    setup() {
 4        onBeforeRouteLeave((to, from, next) => {
 5            
 6            next();
 7        });
 8    }
 9};

4.高级特性与最佳实践

1.路由懒加载
 1const User = () => import('./User.vue');
 2const User = defineAsyncComponent(() => import('./User.vue'));
2.路由元信息(meta)
 1{ path: '/profile', meta: { requireAuth: true } }
 2
3.动态路由
  • 添加路由router.addRoute({ path: '/new', component: New })
  • 删除路由router.removeRoute('route-name')
4.路由组件传参
 1{ path: '/user/:id', component: User, props: true }
 2
5.滚动行为控制
 1const router = createRouter({
 2    scrollBehavior(to, from, savedPosition) {
 3        return savedBehavior || { top: 0 };
 4    }
 5});

5.高频面试题

1.Vue-Router 4.X 与 3.X 的主要区别
  • API命名调整(如new VueRouter() -> createRouter()
  • 组合式API支持(useRouter/useRoute
  • 动态路由API优化(addRoute/removeRoute
2.如何实现路由权限控制
  • 全局守卫 + 元信息
 1router.beforeEach((to, from, next) => {
 2    if(to.meta.requireAuth && !isAuthenticated) next('/login');
 3    else next();
 4});
3.如何处理动态路由加载顺序问题
  • router.isReady():确保初始路由解析完成再挂载应用
 1router.isReady().then(() => app.mount('#app'));
4.如何捕获导航错误
 1router.onError((error) => {
 2    console.error('导航错误', error);
 3});
5.路由组件如何复用并响应参数变化
  • onBeforeRouteUpdate:监听路由参数变化
 1onBeforeRouteUpdate((to, form, next) => {
 2    fetchData(to.params.id);
 3    next();
 4})

6.实战场景示例

 1const dynamicRoutes = [
 2    { path: '/admin', component: Admin, meta: { role: 'admin' } }
 3];
 4if (user.role === 'admin') {
 5    dynamicRoutes.forEach(route => router.addRoute(route));
 6}
 7
 8const Home = () => import(  './Home.vue' );

7.注意事项

  1. this.$router的兼容性:选项式API中仍可用,组合式API推荐useRouter
  2. SSR适配:需使用createMemoryHistory并处理客户端激活
  3. 路由命名冲突:动态路由添加时注意避免重复路径或名称
  4. 导航守卫异步处理:确保调用next()或返回Promise

四、状态管理

1、Vuex

1.Vuex核心概念与工作流程

1.核心角色

  • State:单一状态树,存储全局数据(响应式)
  • Getter:基于State派生的计算属性(类似组件的computed)
  • Mutation:同步修改State的唯一途径(通过commit触发)
  • Action:处理异步操作,提交Mutations(通过dispatch触发)
  • Modules:模块化拆分复杂Store 2.工作流程
 1组件 -> dispatch(Action) -> Action -> commit(Mutation) -> Mutation -> 修改State -> 更新视图

3.Vue4.x对Vue3的支持

  • 兼容Vue3的Composition API,但核心API与Vuex 3.x一致
  • 通过useStore替代this.$store(组合式API中)
 1import { useStore } from 'vuex';
 2export default {
 3    setup() {
 4        const store = useStore();
 5        return { store };
 6    }
 7};
2.核心API与使用

1.定义Store

 1import { createStore } from 'vuex';
 2const store = createStore({
 3    state: { count: 0 },
 4    mutation: {
 5        increment(state) { state.count++; }
 6    },
 7    actions: {
 8        asyncIncrement({ commit }) {
 9            setTimeout(() => commit('increment'), 1000);
10        }
11    },
12    getters: {
13        doubleCount: state => state.count * 2
14    }
15});

2.组件中访问Store

  • 选项式APIthis.$store.state.countmapState/mapGetters辅助函数
  • 组合式APIconst store = useStore(); store.state.count;

3.辅助函数

  • mapState / mapGetters:映射到计算属性
  • mapMutation / MapActions:映射到方法
 1import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
 2export default {
 3    computed: {
 4        ...mapState(['count']),
 5        ...mapGetters(['doubleCount'])
 6    },
 7    methods: {
 8        ...mapMutations(['increment']),
 9        ...mapActions(['asyncIncrement'])
10    }
11};
3.模块化与命名空间

1.模块定义

 1const moduleA = {
 2    namespaced: true, 
 3    state: { ... },
 4    mutation: { ... },
 5    action: { ... }
 6};
 7const store = createStore({
 8    modules: { a: moduleA }
 9});

2.命名空间访问

  • 直接访问store.state.a.moduleData
  • 辅助函数
 1...mapActions('a',['moduleAction']),
 2
 3const { mapActions } = createNamespacedHelpers('a');

3.模块的局部上下文

  • Root State:在模块的Action中通过rootState访问全局状态
  • Root Commit:在模块Actions中通过{ root: true }提交全局Mutation
 1actions: {
 2    localAction({ commit, dispatch, rootState }) {
 3        commit('localMutation');
 4        dispatch('gloabalAction', null, { root: true });
 5    }
 6}
4.高级特性与最佳实践

1.严格模式

 1const store = createStore({ strict: true });
 2

2.插件开发

  • 订阅Mutations
 1store.subscribe((mutation, state) => {
 2    console.log('Mutation:', mutation.type);
 3});
  • 持久化插件(如结合localStorage)
 1const persistPlugin = (store) => {
 2    store.subscribe((mutation, state) => {
 3        localStorage.setItem('vuex-state', JSON.stringify(state));
 4    });
 5};

3.动态注册模块

 1store.registerModule('dynamicModule', { ... });
 2store.unregisterModule('dynamicModule', { ... });
5.高频面试题

1. Vuex与pinia的区别

  • Pinia是Vue官方推荐的新状态管理库,支持Composition API和TypeScript
  • 核心差异
    • Pinia无mutations,直接通过actions修改状态(同步/异步均可)
    • Pinia基于模块化设计(每个Store独立),无需嵌套模块
    • 更简洁的API和TypeScript支持

2. 为什么需要Mutations处理同步,Actions处理异步?

  • 调试工具追踪:确保状态变化的同步记录可追踪
  • 数据可预测性:避免异步操作导致状态变更顺序混乱

3. Vuex如何实现响应式?

  • 底层通过Vue的响应式系统(reactive)实现state的依赖收集和更新触发

4. 如何避免模块命名冲突

  • 使用namespaced: true隔离模块,通过命名空间访问状态和方法

5. 大型项目如何优化Vuex使用?

  • 按功能拆分为模块,结合动态加载(registerModule
  • 使用Getter封装复杂状态逻辑
6.实战使用场景

1.模块化与命名空间

 1const userModel = {
 2    namespaced: true,
 3    state: { name: 'Alice' },
 4    mutations:{
 5        setName(state, name) {
 6            state.name = name;
 7        }
 8    }
 9};
10
11methods:{
12    ...mapActions('user', ['setName']);
13}

2.状态持久化插件

 1const persistedState = localStorage.getItem('vuex-state');
 2const store = createStore({
 3    state: persistedState ? JSON.parse(persistedState) : {}m
 4    plugins: [persistPlugin],
 5});
7.注意事项
  1. 避免直接修改State:必须通过commitdispatch触发变更。
  2. 模块复用:动态注册模块时需要注意生命周期管理(如路由切换时卸载)
  3. 性能优化:避免在Getters中执行高开销计算,使用缓存或拆分逻辑
  4. TypeScript支持:Vuex4对TS支持较弱,推荐使用pinia替代

2、Pinia

1.Pinia核心概念与优势

1. Pinia是什么?

  • Vue官方推荐的新一代状态管理库,替代Vuex,专为Vue3设计,全面支持Composition APITypeScript
  • 核心特点:简洁API、去除了Mutations、模块化天然支持、极致TypeScript友好

2. 核心优势(对比Vuex)

  • 无Mutations:直接通过Actions处理同步/异步逻辑
  • 扁平化结构:多个Store代替嵌套模块,更易维护
  • TypeScript支持:自动推导类型,无需额外配置
  • Devtools集成:支持时间旅行调试和状态快照
  • 轻量高效:体积更小,API更简洁
2.核心API与基本使用

1. 定义Store

  • Options Store(类似Vue选项式API)
 1import { defineStore } from 'pinia';
 2export const useCounterStore = defineStore('counter', {
 3    state: () => ({ count: 0 }),
 4    getters: {
 5        doubleCount: (state) => state.count * 2,
 6    },
 7    actions: {
 8        increment() {
 9            this.count++; 
10        },
11        async asyncIncrement() {
12            setTimeout(() => this.increment(), 1000);
13        },
14    },
15});
  • Setup Store(类似Composition API):
 1export const useUserStore = defineStore('user', () => {
 2    const name = ref('Alice');
 3    const setName = (newName: string) => { name.value = newName; };
 4    return { name, setName };
 5})

2. 在组件中使用Store

 1<script>
 2import { useCounterStore } from '@/stores/counter';
 3const counterStore = useCounterStore();
 4</script>
 5<template>
 6    <div>{{ counterStore.count }}</div>
 7    <button @click="counterStore.increment()">+1</button>
 8</template>
3.核心特性

1. State

  • 响应式状态:通过ref或reactive实现,直接修改自动触发更新
  • 重置状态counterStore.$reset()
  • 批量更新counterStore.$patch({ count: 10 })

2. Getters

  • 类似Vue的computed,自动缓存结果
  • 支持访问其他Store
 1getters: {
 2    combinedInfo() {
 3        const userStore = useUserStore();
 4        return `${userStore.name}: ${this.doubleCount}`;
 5    }
 6}

3. Actions

  • 同步/异步均可:无需区分Mutation和Action
  • 支持相互调用:通过this访问其他Actions
  • 订阅Actions:
 1const unsubscribe = counterStore.$onAction({ name, after, args }) => {
 2    after(() => console.log(`${name} 执行完成,参数:${args}`));
 3}
4.模块化组合

1. 模块化设计

  • 通过多个Store文件天然实现模块化,无需嵌套结构
  • 跨Store调用:
 1import { useCounterStore } from './counter';
 2export const useUserStore = defineStore('user', {
 3    actions: {
 4        asyncWithCounter() {
 5            const counterStore = useCounterStore();
 6            counterStore.increment();
 7        },
 8    },
 9});

2. 动态添加Store

  • 无需显示注册,按需引入即可(天然支持代码分割)
5.插件与高级用法

1. 插件机制

  • 自定义插件(如持久化存储)
 1const persistPlugin = ({ store }) => {
 2    const savedState = localStorage.getItem(store.$id);
 3    if(savedState){
 4        store.$patch(JSON.parse(savedState));
 5    }
 6    store.$subscribe((mutation, state) => {
 7        localStorage.setItem(store.$id, JSON.stringify(state));
 8    });
 9};
  • 注册插件
 1import { createPinia } from 'pinia';
 2const data = createPinia().use(persistPlugin);

2. Devtools支持

  • 默认集成Vue DevTools,可追踪状态变化和Actions调用
6.高频面试题

1. 为什么选择Pinia而不是Vuex?

  • API简洁:去除了Mutation,减少心智负担
  • TypeScript友好:自动类型推导,无需复杂配置
  • 模块化更自然:多个Store代替嵌套模块,结构清晰

2. Pinia如何处理异步操作?

  • 直接在Actions中写异步逻辑(如async/await),无需额外步骤

3. Pinia如何实现响应式?

  • 底层基于Vue3的reactive和ref,保证状态变更自动触发更新

4. 如何实现状态持久化?

  • 通过插件拦截$subscribe$onAction,结合localStorage

5. Pinia如何支持TypeScript?

  • Store定义自动推导类型,组件中通过store.xxx直接获得类型提示
7.实战场景示例

1. 用户认证状态管理

 1export const useAuthStore = defineStore('auth', {
 2    state: () => ({ token: null, user: null }),
 3    actions: {
 4        async login(username: string, password: string) {
 5            const res = await api.login(usename,password);
 6            this.token = res.token;
 7            this.user = res.user;
 8        },
 9        logout() {
10            this.$reset();
11        },
12    },
13});

2. 跨Store组合逻辑

 1export const useCartStore('cart', {
 2    actions: {
 3        checkout() {
 4            const authStore = useAuthStore();
 5            if(authStore.user) throw new Error('请先登录');
 6            
 7        },
 8    },
 9});
8.注意事项
  1. 避免直接修改Store实例:使用Actions或$patch确保状态变更
  2. 性能优化:拆分高频变更状态到独立Store,减少渲染影响
  3. 合理设计Store:按业务功能划分Store,避免单一Store过于臃肿
  4. TypeScript最佳实践:明确标注类型(如state:() => ({ count: 0 as number })

五、性能优化

1.Vue3核心优化机制

1.响应式系统升级
  • 基于Proxy替代Vue2的Object.defineProperty,支持动态属性添加和数组索引修改的监听
  • 惰性依赖追踪:仅对实际用到的属性触发更新,减少不必要的渲染
2.编译优化
  • 静态提升:将静态节点(无动态绑定的元素)提升到渲染函数外,避免重复创建
  • 补丁标志:在虚拟DOM中标记动态绑定的类型(如class、style、props),减少Diff对比范围
  • Block Tree优化:将模版划分为动态和静态区块,仅追踪动态区块的变化
  • 缓存事件处理程序:如@click的时间处理函数会被缓存,避免重复生成

2.组件级优化策略

1.渲染控制
  • v-once:静态内容只渲染一次
 1<div v-once>永不更新的内容</div>

- v-memo(Vue3.2+):依赖不变时跳过更新

 1<div v-memo="[value]">{{ value }}</div>  <!-- 仅当value变化时更新 -->
  • v-show:高频切换(CSS显示隐藏)
  • v-if:低频切换(销毁/重建组件)
2.组件设计优化
  • 细粒度拆分:隔离高频更新组件
  • 异步组件:延迟加载非关键组件
 1const Modal = defineAsyncComponet(() => import('./Modal.vue'));
3.状态管理优化
  • shallowRef/shalloReactive:非深度响应式数据
 1const largeObj = shallowRef({ ... }) 
  • 避免大型响应式对象:解构为独立ref
  • 使用markRaw跳过响应式转换
 1const staticData = markRaw({ ... }) 

3.资源与加载优化

1.代码分割
  • 路由级懒加载(Vue Router
 1{ path: '/dashboard', component: () => import('./Dashboard.vue') }
  • 组件级懒加载(defineAsyncComponent
  • 第三方库按需加载:
 1import { debounce } from 'lodash-es'; 
2.Tree Shaking支持
  • 使用ES模块语法(ESM)
  • 避免副作用代码:
 1pakage.json 中标记 "sideEffects": false
3.预加载关键资源
 1<!-- 预加载首屏关键组件 -->
 2<link rel="preload" as="script" href="/src/components/Critical.vue">
 3

4.运行时性能优化

1.列表渲染优化
  • 必须提供key:
 1<li v-for="item in items" :key="item.id">{{ item.text }}</li>
  • 虚拟滚动(vue-virtual-scroller)
 1<RecycleScroller :items="largeList" item-size="50">
 2    <template #default="{ item }">{{ item.text }}</template>
 3</RecycleScroller>
  • 避免v-for与v-if共用(优先用computed过滤数据)
2.计算与侦听优化
  • computed缓存:替代模板内复杂表达式
  • 避免深度监听大型对象:
 1watch(data, callback, { deep: false }) 
  • watchEffect自动依赖追踪:
 1watchEffect(() => console.log(state.count)) 
3.事件处理优化
  • 高频事件使用防抖/节流
 1import { debounce } from 'lodash-es';
 2methods: { search: debounce(fn, 300) }

5.架构级优化

1.服务端渲染(SSR)
  • 使用Nuxt.js实现
 1npx nuxi init my-ssr-app
  • 优势:提升首屏加载速度 & SEO
2.静态站点生成(SSG)
  • 使用VitePress/VuePress:
 1npm init vitepress
  • 预生成静态页面,适合内容型网站
3.CDN与缓存策略
  • 静态资源添加Content Hash:
 1app.3a88b9e2.js # 文件名包含hash
  • 设置长期缓存:
 1location /assets {
 2    expires 1y;
 3    add_header Cache-Control "public";
 4}

6.工具链优化

1.现代构建工具
  • Vite:基于ESM的极速开发体验
 1npm create vite@lastest
  • 生产构建优化:
 1export default {
 2    build: {
 3        minify: 'terser', 
 4        brtliSize: true,  
 5        chunkSizeWarningLimit: 1000 
 6    }
 7}
2.性能分析工具
  • Chorme DevTools Performance 面板
  • Vue DevTools 性能追踪
  • Lighthouse 性能评分
 1lighthouse http:

7.高频面试题

1.Vue3比Vue2快在哪里?
  • 响应式:Proxy替代defineProperty
  • 编译:Patch Flag/Block Tree减少Diff范围
  • 体积:Tree Shaking支持更佳
2.如何优化长列表性能?
  • 虚拟滚动 + 唯一key + 避免响应式嵌套
3.v-memo的使用场景
  • 表格行渲染
  • 大型表单字段
  • 重复渲染的子组件
4.什么时候用shallowRef?
  • 大型对象/数组(如1000+条目的列表数据)
5.SSR解决了什么问题?
  • 首屏加载白屏问题
  • SEO不友好问题

8.实战优化示例

1.虚拟滚动实现
 1<template>
 2    <VirtualList :items="items" :item-size="50" height="300px">
 3        <template #default="{ item }">
 4            <ListItem :item="item" />
 5        </template>
 6    </VirtualList>
 7</template>
2.状态更新批处理
 1import { nextTick } from 'vue';
 2async function batchUpdate() {
 3    state.a = 1;
 4    state.b = 2;
 5    await nextTick() 
 6    
 7}
3.Web Worker处理CPU密集型任务
 1const woker = new Worker('./worker.js');
 2worker.postMessage(data);
 3worker.onmessage = e => { state.result = e.data }

9.优化原则总结

  1. 量度优先:用Lighthouse/Vue Devtools定位瓶颈
  2. 渐进优化:优先解决最大性能瓶颈(如长列表/包体积)
  3. 平衡之道:避免过度优化牺牲可维护性
  4. 更新策略
方法使用场景
v-memo精确控制子组件更新条件
shallowRef大型非深度响应数据
markRaw永远不需要响应式的数据
defineAsyncComponent延迟加载非首屏组件

六、Vue2和Vue3的区别

1.架构设计区别

特性Vue2Vue3优势
响应式系统Object.definePropertyProxy支持动态属性/数组索引监听,性能更优
代码组织Options APIComposition API逻辑复用更灵活,类型推导更友好
源码组织Flow 类型系统TypeScript 重写更好的类型支持和源码可维护性
包体积全量引入(22.5kb)按需引入(<10kb)Tree Shaking 减少 41% 体积

2.响应式系统升级

1.Vue的局限性
 1this.$set(this.obj, 'newProp', value);
 2
 3this.$set(this.arr, index, value);
2.Vue3的Proxy实现
 1const proxy = new Proxy(data, {
 2    get(target, key) {  },
 3    set(target, key, value) {  }
 4})
  • 优势
    • 支持动态属性增删/数组索引修改
    • 无需初始化深度遍历(惰性依赖追踪)
    • 内存占用减少50%(基于基准测试)

3.Composition API vs Options API

1.Options API 痛点
 1export default {
 2    data() {
 3        return {
 4            count: 0
 5        }
 6    },
 7    methods: { increment() {...} },
 8    computed: { double() {...} }
 9}
2.Composition API 解决方案
 1import { ref, computed } from 'vue';
 2export function useCounter() {
 3    const count = ref(0);
 4    const double = computed(() => count.value * 2);
 5    function increment() { count.value++ }
 6    return { count, double, increment }; 
 7}
  • 核心优势
    • 逻辑复用(自定义Hook)
    • 更好的TypeScript支持
    • 代码组织更灵活(按功能而非选项)

4.性能优化对比

优化方向Vue2Vue3
编译优化全量 DiffPatch Flags 标记动态节点
静态提升静态节点提升到渲染函数外部
Tree Shaking有限支持核心 API 可摇树优化
内存占用较高减少 50%(Proxy 惰性依赖)

编译优化示例

 1export function render() {
 2    return (_openBlock(), _createBlock("div", null, [
 3        _createVNode("span", null, "静态内容"), 
 4        _createVNode("span", { class: _ctx,dynamicClass }, null, 2 )
 5    ]))
 6}

5.生命周期变化

Vue2Vue3​ (Composition API)变化说明
beforeCreatesetup()被 setup 替代
createdsetup()被 setup 替代
beforeMountonBeforeMount改名
mountedonMounted改名
beforeUpdateonBeforeUpdate改名
updatedonUpdated改名
beforeDestroyonBeforeUnmount改名(语义更准确)
destroyedonUnmounted改名(语义更准确)
errorCapturedonErrorCaptured改名

使用示例

 1import { onMounted, onUnmounted } from 'vue'
 2export default {
 3  setup() {
 4    onMounted(() => console.log('组件挂载'))
 5    onUnmounted(() => console.log('组件卸载'))
 6  }
 7}

6.新特性与API

1.Fragment(碎片)
 1<!-- Vue3 支持多根节点 -->
 2<template>
 3  <header>...</header>
 4  <main>...</main>
 5  <footer>...</footer>
 6</template>
2.Teleport(传送门)
 1<teleport to="#modal-container">
 2    <div class="modal">模态框内容</div>
 3</teleport>
3.Suspense(异步组件)
 1<Suspense>
 2  <template #default><AsyncComponent /></template>
 3  <template #fallback><div>Loading...</div></template>
 4</Suspense>
4.自定义渲染器API
 1import { createRenderer } from 'vue';
 2const { render } = createRenderer({  })

7.生态与工具链

领域Vue2Vue3说明
官方路由vue-router 3.xvue-router 4.x适配 Composition API
状态管理Vuex 3.xVuex 4.x / ​PiniaPinia 为官方推荐新方案
构建工具Vue CLIViteVite 开发速度提升 10 倍+
SSR 框架Nuxt 2Nuxt 3全面支持 Vue3 生态

8.迁移升级攻略

1.兼容方案
  • @vue/compat库提供兼容模式(Vue2行为 + Vue3特性)
  • 逐步替换废弃的API(eventBus -> mitt,Vue.extend -> defineComponent)
2.自动迁移工具
 1npm install -g @vue/compat
 2vue-cli-service upgrade  # 自动检测并修复部分 API
3.分步骤迁移

 

 

9.高频面试题

1.为什么Vue3用Proxy替代defineProperty?
  • 解决动态属性/数组监听问题
  • 初始化性能提升(无需递归遍历)
  • 内存占用更低
2.Composition API 解决了什么问题?
  • 逻辑复用困难(Mixins的命名冲突/来源不清)
  • Options API的逻辑碎片化
  • TypeScript类型推导支持弱
3.Vue3的模版编译优化有哪些?
  • Patch Flags(动态节点标记)
  • 静态节点提升(减少重复创建)
  • Block Tree(跳过静态子树对比)
4.Vue3对TypeScript的支持改进
  • 源码使用TS重写
  • Composition API 完美支持类型推导
  • defineComponent提供组件类型申明
5.Vue2项目如何升级Vue3?
  • 使用@/vue/compat过渡
  • 逐步替换废弃API($children,filters等)
  • 优先迁移新组件,逐步重构旧组件

七、SPA

1.核心概念

1.定义与特点
  • 单页面应用:整个应用只有一个HTML文件,通过动态替换DOM内容实现”页面”切换
  • 核心优势
    • 无刷新跳转(流畅用户体验)
    • 前后端分离开发
    • 减轻服务器渲染压力
  • 主要挑战
    • 首屏加载性能
    • SEO优化难度
    • 路由管理复杂度
2.SPA与MPA对比
特性SPAMPA (多页面应用)​
页面数量1 个 HTML多个 HTML
页面跳转前端路由控制,无刷新整页刷新
数据请求Ajax/Fetch 局部获取数据每次跳转加载完整页面
开发复杂度高(需前端路由、状态管理等)
SEO 支持差(需额外优化)

2.高频面试题

1.SPA首屏加载优化有哪些方案?
  • 路由懒加载 + 组件懒加载
  • 资源预加载/预取
  • CDN加速静态资源
  • 开启Gzip/Brotli压缩
  • 服务端渲染(SSR)
2.如何解决SPA的SEO问题?
  • 预渲染(Prerender)
  • 服务端渲染(Nustjs)
  • 动态渲染(针对爬虫单独处理)
  • 静态站点生成(SSG)
3.Vue Router的导航守卫执行顺序
 1全局 beforeEach -> 路由 beforeEnter -> 组件 beforeRouteEnter -> 全局 beforeResolve -> 全局 afterEach -> 组件 beforeRouteUpdate
4.如何处理权限路由?
 1router.beforeEach(async (to) => {
 2    if (!hasAuthInfo) await fetchUserPermissions();
 3    if (to.meta.requiresAdmin && !isAdmin) return '/no-permission';
 4})
5.SPA如何保持登录状态?
  • JWT存储于localStorage + 刷新Token机制
  • 结合HttpOnly Cookie增强安全性
  • Token过期自动跳转登录页

八、SSR

1.SSR核心概念与原理

1.服务端渲染 vs 客户端渲染
对比维度SSRCSR (SPA)​
渲染位置服务端生成完整 HTML客户端 JS 动态生成 DOM
首屏时间快(直接输出 HTML)慢(需加载 JS 并执行)
SEO 支持优(爬虫直接抓取 HTML)差(需额外处理)
服务器压力高(每次请求需渲染)低(仅提供静态资源)
开发复杂度高(需处理同构、服务器环境等)低(纯前端开发)
2.Vue SSR 工作原理

浏览器服务器Vue 应用发送页面请求执行 createSSRApp()渲染组件树生成 HTML返回包含数据的 HTML激活(Hydration) 交互变为可交互 SPA浏览器服务器Vue 应用

3.关键流程说明
  • 服务端渲染renderToString()生成静态HTML
  • 客户端激活createSSRApp().mount()接管DOM添加事件
  • 数据预取:在渲染前获取页面所需数据(避免客户端二次请求)

2.Nuxt.js 3 核心使用

1.项目结构与约定
 1├─ .nuxt/         # 构建生成
 2├─ components/    # 公共组件
 3├─ composables/   # 复用逻辑
 4├─ layouts/       # 布局组件
 5├─ middleware/    # 路由中间件
 6├─ pages/         # 自动路由支持动态路由
 7├─ plugins/       # 插件注册
 8├─ public/        # 静态资源
 9├─ server/        # API 路由
10└─ nuxt.config.ts # 配置文件
2.服务端生命周期
 1useAsyncData('key', async () => {
 2    const data = await $fetch('/api/data')
 3    return data;
 4})
 5
 6onServerPrefetch(async () => {
 7    
 8})
3.渲染模式配置
 1export default defineNustConfig({
 2    ssr: true, 
 3    
 4    routeRules: {
 5        '/static': { prerender: true },
 6        '/spa/**': { ssr: false }
 7    }
 8});

3.数据获取与状态管理

1.数据预取策略
方法执行位置特点
useAsyncData服务端/客户端自动防止重复获取,key 唯一化
useFetch服务端/客户端封装了 useAsyncData + $fetch
onServerPrefetch仅服务端组合式 API 专用,类似 vue2 的 serverPrefetch
nuxtServerInit仅服务端(Pinia)初始化 store 全局数据
2.Pinia状态同步
 1export const useUserStore = defineStore('user', {
 2    state: () => ({ token: null }),
 3    actions: {
 4       
 5        async nustServerInit() {
 6            this.token = await getTokenFormCookie();
 7        }
 8    }
 9});
10

4.性能优化策略

1.渲染层优化
  • 组件缓存
 1export default {
 2    render: {
 3        componentCache: {
 4            max: 1000,
 5            maxAge: 1000 * 60 * 15 
 6        }
 7    }
 8}
  • 页面级缓存
 1export default defineNitroConfig({
 2    storage: {
 3        redis: { driver: 'redis', url: 'redis://localhost:6379'}
 4    },
 5    routeRules: {
 6        '/': { cache: { maxAge: 60 } } 
 7    }
 8})
2.资源加载优化
  • 预加载关键资源
 1<head>
 2    <link rel="preload" href="/main.css" as="style">
 3    <link ref="modulepreload" href="/vendor.js">
 4</head>
  • HTTP/2 服务端推送
 1Link </app.css>; rel=preload; as=style
2.流式渲染
 1const stream = renderToNodeStream(app);
 2stram.pipe(res, { end: false });

5.错误处理与调试

1.全局错误捕获
 1export default defineNustPlugin(nustApp => {
 2    nustApp.vueApp.config.errorHandler = (err) => {
 3        console.error('客户端错误:', err);
 4    }
 5})
 6
 7export default defineNitroPluign((nitroApp) => {
 8    nitroApp.hooks.hook('error', (err) => {
 9        logErrorToService(err);
10    })
11})
2.Sentry集成
 1modules: ['@nustjs/sentry'],
 2sentry: {
 3    dsn: 'YOUR_DSN',
 4    tracing: true 
 5}

6.安全最佳实践

1.XSS防护
  • 避免在服务端渲染中使用v-html
  • 使用vue-basic-sanitize过滤用户内容
2.CSRF防护
 1export default defineEventHandler(event => {
 2  if (!isValidCSRF(event)) {
 3    throw createError({ status: 403, message: 'Forbidden' })
 4  }
 5  return { data: '安全数据' }
 6})
3.CORS配置
 1export default {
 2    nitro: {
 3        middleware: [
 4            corsHander({
 5                origin: ['http://yourdomain.com'],
 6                methods: ['GET', 'POST']
 7            })
 8        ]
 9    }
10}

7.高阶应用场景

1.混合渲染(Hydrid Rendering)
 1export default {
 2    routeRules: {
 3        
 4        'privacy': { prerender: true },
 5        
 6        '/dashboard/**': { ssr: false },
 7        
 8        '/products': { swr: 3600 }
 9    }
10}
2.边缘渲染(Edge-Side Renddering)
 1npx nuxi build --preset=vercel-edge
3.微前端集成
 1export default defineComponent({
 2    async setup() {
 3        const microApp = await loadMicroApp('react-subapp', '#container');
 4    }
 5})

8.高频面试题

1.SSR的核心优势
  • 提升首屏速度
  • 更好的SEO
  • 更稳定的用户体验
2.hydration过程可能出现的问题
  • 客户端和服务端渲染的DOM结构不一致导致hydration失败
  • 解决方案:
    • 避免在<template>中使用随机数
    • 确保服务端/客户端初始状态一致
    • 用v-if替代v-show处理不可见元素
3.如何处理异步数据的服务端渲染?
  • 使用useAsyncDataonServerPrefetch在渲染前获取数据
  • 通过__NUXT__.state注入到HTML供客户端激活
4.如何优化高并发下的SSR性能?
  • 组件级缓存+页面级缓存
  • 流式渲染减少TTFB(首字节时间)
  • 负载均衡+水平扩展服务器
5.Nuxt3相比Nuxt2的重大改进
  • 基于Vite的极速HMR
  • 支持混合渲染和增量静态生成
  • Nitro引擎提供Serverless/Edge
  • 更好的TypeScript集成

9.实战注意事项

1.避免全局副作用
 1let count = 0;
 2export const useCounter = () => ({ count: ++count })
 3
 4export const useCounter = () => {
 5    const count = ref(0);
 6    return { count };
 7}
2.环境区分处理
 1const runtimeConfig = useRuntimeConfig();
 2const apiBase = process.server ? runtimeConfig.apiSecret : runtimeConfig.public.apiBase;
3.性能监控指标
指标工具目标值
TTFB (首字节时间)Chrome DevTools<200ms
FCP (首次内容渲染)Lighthouse<1s
TTI (可交互时间)WebPageTest<3s
Hydration 时间Vue Devtools<500ms

个人笔记记录 2021 ~ 2025