以下为Vue3面试进阶篇考察点总结,具体知识点不会太详细,主要梳理面试核心考察点,为面试做准备。
Vue进阶
一、keep-alive
1.核心作用和使用场景
1.作用
- 缓存组件实例:避免重复销毁和创建,保留组件状态(如
DOM结构、响应式数据、事件监听
) - 提升性能:适用于需要频繁切换但状态需保留的组件(如
Tab页、表单填写页
)
2.使用方式
<template>
<keep-alive :include="['ComponentA', 'ComponentB']" :max="5">
<component :is="currentComponent"></component>
</keep-alive>
</template>
2.生命周期钩子变化
- 新增钩子(仅在被缓存的组件中触发)
- onActivated:组件被激活(插入DOM)时触发。
- onDeactivated:组件被停用(移除DOM)时触发
- 执行顺序:
- 首次加载:
onCreate->onMounted->onActivated
- 切换离开:
onDeactivated
- 再次进入:
onActivated
- 彻底销毁:
onUnmounted
- 首次加载:
3.关键配置属性
1.include
- 匹配组件名称(name选项),仅缓存匹配的组件
- 支持字符串、正则、数组
<!-- 缓存以 "Test" 开头的组件 -->
<keep-alive :include="/^Test/">
2.exclude
- 排除指定组件,优先级高于include
3.max
- 最大缓存实例数,超出时按LRU(最近最少使用)策略淘汰旧实例
- LUR原理:有限淘汰最久未访问的实例
4.高频面试题
1.keep-alive实现原理
- 缓存机制:通过Map或Object缓存组件vnode实例,渲染时直接从缓存中取
- DOM处理:被缓存的组件移除时,不销毁DOM,仅隐藏(
display: none
)
2.如何动态控制组件缓存
- 方案1:绑定动态include/exclude(响应式变量)
<keep-alive :include="cachedComponents">
- 方案2:通过key强制重新渲染(改变key会销毁旧实例)
<component :is="currentComponent" :key="componentKey">
3.keep-alive如何结合路由使用
- 搭配router-view
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" />
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive" />
</router-view>
- 路由配置:通过meta字段标记需缓存的页面
{ path: '/home', component: Home, meta: { keepAlive: true } }
4.缓存组件如何更新数据
- onActivated中刷新数据
onActivated(() => {
fetchData(); // 重新请求数据
});
5.max属性的作用及淘汰策略
- 作用:避免内存无限增长,限制最大缓存实例
- 淘汰策略:LRU(最近最少使用),优先移除最久未被访问的实例
5.注意事项
- 组件必须设置name选项:否则include/exclude无法匹配
- 避免内存泄漏:及时清理不需要缓存的组件(如通过max或动态include)
- SSR不兼容:keep-alive仅在客户端渲染中生效
- 缓存组件的状态保留:表单内容等会被保留,需手动重置或通过key强制更新
6.实战实例
<template>
<button @click="toggleComponent">切换组件</button>
<keep-alive :include="cachedComponents" :max="3">
<component :is="currentComponent" :key="currentComponent" />
</keep-alive>
</template>
<script setup>
import { ref } from 'vue';
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
const currentComponent = ref('ComponentA');
const cachedComponents = ref(['ComponentA', 'ComponentB']);
const toggleComponent = () => {
currentComponent.value = currentComponent.value === 'ComponentA' ? 'ComponentB' : 'ComponentA';
};
</script>
二、异步组件
1.核心概念与使用方式
1.定义异步组件
defineAsyncComponent
函数(Vue3推荐方式)
import { defineAsyncComponent } from 'vue';
const AsyncCom = defineAsyncComponent(() => import('./MyComponent.vue'));
- 动态
import()
语法(结合构建工具如Webpack/Vite实现代码分割)
const AsyncComp = defineAsyncComponent({
loader: () => import('./MyComponent.vue'),
loadingComponent: loadingSpinner, // 加载中组件
errorComponent: ErrorDisplay, // 错误组件
delay: 1000, // 延迟显示loading(防闪烁)
timeout, // 超时时间
})
2.Suspense组件
- 统一管理异步组件(如异步组件或异步setup函数):
<template>
<Suspense>
<template #default>
<AsyncComp />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
2.高频面试题
1.异步组件的核心作用
- 按需加载:减少初始包体积,提升首屏加载速度
- 性能优化:结合代码分割(
Code Spliting
)动态加载非关键组件
2.如何配置异步组件的加载状态和错误处理?
loadingComponent
:显示加载中的UI(如loading动画)errorComponent
:加载失败时显示错误提示delay
:延迟显示loading组件,避免快速加载时闪烁timeout
:超时后触发错误组件
3.Suspense和异步组件的关系
- Suspense:内置组件,用于统一管理异步组件的加载状态(如多个异步组件并行加载)
- 异步组件:通过
defineAsyncComponent
定义,由Suspense
控制占位内容
4.如何实现组件加载失败后的重试逻辑
- 工厂函数返回Promise:在loader中捕获错误并重试
const Async = defineAsyncComponent({
loader: () => import('./MyComponent.vue')
.catch(() => {
// 重试逻辑
return retryImport();
})
})
5.异步组件在路由懒加载中的应用
- Vue Router配置
const router = createRouter({
route: [{
path: '/profile',
component: () => import('./Profile.vue'); // 直接动态导入
// 或使用defineAsyncComponent
component: defineAsyncComponent(() => import('./Profile.vue'))
}]
})
6.Vue3异步组件与Vue2的差异
- 语法差异:Vue3废弃
Vue.component('async-comp',() => import(...))
,改用defineAsyncComponent
- 功能增强:Vue3支持更细颗粒度的加载状态管理和
Suspense
集成
3.底层原理优化
1.代码分割原理
- 构建工具(如webpack)将动态
import()
的模块拆分为独立chunk
,运行时按需加载
2.异步组件生命周期
- 加载阶段:触发loader -> 下载loader -> 初始化组件
- 缓存机制:已加载的组件实例会被缓存,避免重复加载
3.性能优化策略
- 预加载(prefetch):通过Webpack魔法注释标记非关键资源
() => import(/* webpackPrefetch: true */ './MyComponent.vue')
- 懒加载阈值:结合路由或用户行为预测延迟加载组件
4.注意事项
- 组件命名:异步组件需显式申明
name
选项,以便调试和keep-alive
匹配 - SSR限制:异步组件在服务端渲染中需特殊处理(如占位内容)
- 错误边界:结合
onErrorCaptured
全局捕获异步组件错误 - 过度分割:避免过多小模块导致HTML请求激增
5.实战代码实例
// 异步组件定义
const AsyncModal = defineAsyncComponent({
lodaer: () => import('./Modal.vue').catch((err) ==> {
console.log('加载失败,3s后重试...');
return new Promise(resolve => {
setTimeout(() => resolve(import('./Modal.vue')), 3000);
})
}),
loadingComponent: LoadingSpainner,
delay: 200,
timeout: 5000
});
// 在组合式API中使用
export default {
setup() {
const showModal = ref(false);
return { showModal, AsyncModal };
}
}
6.应用场景
- 大型应用模块懒加载:如管理后台的复杂表单/图表组件
- 条件渲染组件:用户交互后才加载的非必要组件(如弹窗)
- 路由级懒加载:结合Vue Router提升首屏性能
三、Vue-Router
1.Vue-Router 4.X核心变化
1.创建路由实例
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(), // 或 createWebHashHistory
routes: [...]
});
2.组合式API支持
- useRouter():获取路由实例(替代
this.$router
) - useRoute():获取当前路由对象(替代
this.$route
)
2.路由配置与核心概念
1.动态路由
{ path: '/user/:id', component: User };
// 获取参数:route.params.id
2.嵌套路由
{
path: '/parent',
component: Parent,
children: [
{ path: 'child', component: Child }
]
}
3.命名路由与编程式导航
router.push({ name: 'user', params: { id: 1 } });
4.路由模式
createWebHistory()
:History模式(需服务器支持)createWebHashHistory()
:Hash模式createMemoryHistory()
:SSR或测试环境
5.重定向与别名
{ path: '/home', redirect: '/' }
{ path: '/', alias: 'home' }
3.导航守卫
1.全局守卫
router.beforeEach((to, from, next) => { ... })
router.afterEach((to, from) => { ... })
router.beforeResolve()
2.路由独享守卫
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => { ... }
}
3.组件内守卫
onBeforeRouteUpdate
:路由参数变化onBeforeRouteLeave
:离开组件前
import { onBeforeRouteLeave } from 'vue-router';
export default {
setup() {
onBeforeRouteLeave((to, from, next) => {
// 清理逻辑
next();
});
}
};
4.高级特性与最佳实践
1.路由懒加载
const User = () => import('./User.vue');
const User = defineAsyncComponent(() => import('./User.vue'));
2.路由元信息(meta)
{ path: '/profile', meta: { requireAuth: true } }
// 在导航守卫中访问:to.meta.requiresAuth
3.动态路由
- 添加路由:
router.addRoute({ path: '/new', component: New })
- 删除路由:
router.removeRoute('route-name')
4.路由组件传参
{ path: '/user/:id', component: User, props: true }
// 组件通过props:['id'] 接收
5.滚动行为控制
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
return savedBehavior || { top: 0 };
}
});
5.高频面试题
1.Vue-Router 4.X 与 3.X 的主要区别
- API命名调整(如
new VueRouter() -> createRouter()
) - 组合式API支持(
useRouter/useRoute
) - 动态路由API优化(
addRoute/removeRoute
)
2.如何实现路由权限控制
- 全局守卫 + 元信息
router.beforeEach((to, from, next) => {
if(to.meta.requireAuth && !isAuthenticated) next('/login');
else next();
});
3.如何处理动态路由加载顺序问题
router.isReady()
:确保初始路由解析完成再挂载应用
router.isReady().then(() => app.mount('#app'));
4.如何捕获导航错误
router.onError((error) => {
console.error('导航错误', error);
});
5.路由组件如何复用并响应参数变化
onBeforeRouteUpdate
:监听路由参数变化
onBeforeRouteUpdate((to, form, next) => {
fetchData(to.params.id);
next();
})
6.实战场景示例
// 动态添加路由(权限控制)
const dynamicRoutes = [
{ path: '/admin', component: Admin, meta: { role: 'admin' } }
];
if (user.role === 'admin') {
dynamicRoutes.forEach(route => router.addRoute(route));
}
// 路由懒加载与预加载(webpack魔法注释)
const Home = () => import( /* webpackPrefetch: true */ './Home.vue' );
7.注意事项
- this.$router的兼容性:选项式API中仍可用,组合式API推荐useRouter
- SSR适配:需使用createMemoryHistory并处理客户端激活
- 路由命名冲突:动态路由添加时注意避免重复路径或名称
- 导航守卫异步处理:确保调用next()或返回Promise
四、状态管理
1、Vuex
1.Vuex核心概念与工作流程
1.核心角色
State
:单一状态树,存储全局数据(响应式)Getter
:基于State派生的计算属性(类似组件的computed)Mutation
:同步修改State的唯一途径(通过commit触发)Action
:处理异步操作,提交Mutations(通过dispatch触发)Modules
:模块化拆分复杂Store
2.工作流程
组件 -> dispatch(Action) -> Action -> commit(Mutation) -> Mutation -> 修改State -> 更新视图
3.Vue4.x对Vue3的支持
- 兼容Vue3的
Composition API
,但核心API与Vuex 3.x一致 - 通过
useStore
替代this.$store
(组合式API中)
import { useStore } from 'vuex';
export default {
setup() {
const store = useStore();
return { store };
}
};
2.核心API与使用
1.定义Store
import { createStore } from 'vuex';
const store = createStore({
state: { count: 0 },
mutation: {
increment(state) { state.count++; }
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => commit('increment'), 1000);
}
},
getters: {
doubleCount: state => state.count * 2
}
});
2.组件中访问Store
- 选项式API:
this.$store.state.count
或mapState/mapGetters
辅助函数 - 组合式API:
const store = useStore(); store.state.count;
3.辅助函数
mapState / mapGetters
:映射到计算属性- mapMutation / MapActions:映射到方法
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
computed: {
...mapState(['count']),
...mapGetters(['doubleCount'])
},
methods: {
...mapMutations(['increment']),
...mapActions(['asyncIncrement'])
}
};
3.模块化与命名空间
1.模块定义
const moduleA = {
namespaced: true, // 启用命名空间
state: { ... },
mutation: { ... },
action: { ... }
};
const store = createStore({
modules: { a: moduleA }
});
2.命名空间访问
- 直接访问:
store.state.a.moduleData
- 辅助函数
...mapActions('a',['moduleAction']),
// 或通过createNamespacedHelpers
const { mapActions } = createNamespacedHelpers('a');
3.模块的局部上下文
- Root State:在模块的Action中通过rootState访问全局状态
- Root Commit:在模块Actions中通过
{ root: true }
提交全局Mutation
actions: {
localAction({ commit, dispatch, rootState }) {
commit('localMutation');
dispatch('gloabalAction', null, { root: true });
}
}
4.高级特性与最佳实践
1.严格模式
const store = createStore({ strict: true });
// 直接修改state会抛出错误(仅限开发环境)
2.插件开发
- 订阅Mutations
store.subscribe((mutation, state) => {
console.log('Mutation:', mutation.type);
});
- 持久化插件(如结合localStorage)
const persistPlugin = (store) => {
store.subscribe((mutation, state) => {
localStorage.setItem('vuex-state', JSON.stringify(state));
});
};
3.动态注册模块
store.registerModule('dynamicModule', { ... });
store.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.模块化与命名空间
// user模块
const userModel = {
namespaced: true,
state: { name: 'Alice' },
mutations:{
setName(state, name) {
state.name = name;
}
}
};
// 组件中调用
methods:{
...mapActions('user', ['setName']);
}
2.状态持久化插件
const persistedState = localStorage.getItem('vuex-state');
const store = createStore({
state: persistedState ? JSON.parse(persistedState) : {}m
plugins: [persistPlugin],
});
7.注意事项
- 避免直接修改State:必须通过
commit
或dispatch
触发变更。 - 模块复用:动态注册模块时需要注意生命周期管理(如路由切换时卸载)
- 性能优化:避免在
Getters
中执行高开销计算,使用缓存或拆分逻辑 - TypeScript支持:Vuex4对TS支持较弱,推荐使用
pinia
替代
2、Pinia
1.Pinia核心概念与优势
1. Pinia是什么?
- Vue官方推荐的新一代状态管理库,替代Vuex,专为Vue3设计,全面支持
Composition API
和TypeScript
- 核心特点:简洁API、去除了
Mutations
、模块化天然支持、极致TypeScript
友好
2. 核心优势(对比Vuex)
- 无Mutations:直接通过
Actions
处理同步/异步逻辑 - 扁平化结构:多个
Store
代替嵌套模块,更易维护 - TypeScript支持:自动推导类型,无需额外配置
- Devtools集成:支持时间旅行调试和状态快照
- 轻量高效:体积更小,API更简洁
2.核心API与基本使用
1. 定义Store
- Options Store(类似Vue选项式API)
// stores/counters.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++; // 直接修改状态
},
async asyncIncrement() {
setTimeout(() => this.increment(), 1000);
},
},
});
- Setup Store(类似Composition API):
export const useUserStore = defineStore('user', () => {
const name = ref('Alice');
const setName = (newName: string) => { name.value = newName; };
return { name, setName };
})
2. 在组件中使用Store
<script>
import { useCounterStore } from '@/stores/counter';
const counterStore = useCounterStore();
</script>
<template>
<div>{{ counterStore.count }}</div>
<button @click="counterStore.increment()">+1</button>
</template>
3.核心特性
1. State
- 响应式状态:通过
ref或reactive
实现,直接修改自动触发更新 - 重置状态:
counterStore.$reset()
- 批量更新:
counterStore.$patch({ count: 10 })
2. Getters
- 类似Vue的computed,自动缓存结果
- 支持访问其他Store
getters: {
combinedInfo() {
const userStore = useUserStore();
return `${userStore.name}: ${this.doubleCount}`;
}
}
3. Actions
- 同步/异步均可:无需区分Mutation和Action
- 支持相互调用:通过this访问其他Actions
- 订阅Actions:
const unsubscribe = counterStore.$onAction({ name, after, args }) => {
after(() => console.log(`${name} 执行完成,参数:${args}`));
}
4.模块化组合
1. 模块化设计
- 通过多个Store文件天然实现模块化,无需嵌套结构
- 跨Store调用:
// store/user.ts
import { useCounterStore } from './counter';
export const useUserStore = defineStore('user', {
actions: {
asyncWithCounter() {
const counterStore = useCounterStore();
counterStore.increment();
},
},
});
2. 动态添加Store
- 无需显示注册,按需引入即可(天然支持代码分割)
5.插件与高级用法
1. 插件机制
- 自定义插件(如持久化存储)
const persistPlugin = ({ store }) => {
const savedState = localStorage.getItem(store.$id);
if(savedState){
store.$patch(JSON.parse(savedState));
}
store.$subscribe((mutation, state) => {
localStorage.setItem(store.$id, JSON.stringify(state));
});
};
- 注册插件:
import { createPinia } from 'pinia';
const 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. 用户认证状态管理
// store/auth.ts
export const useAuthStore = defineStore('auth', {
state: () => ({ token: null, user: null }),
actions: {
async login(username: string, password: string) {
const res = await api.login(usename,password);
this.token = res.token;
this.user = res.user;
},
logout() {
this.$reset();
},
},
});
2. 跨Store组合逻辑
// store/cart.ts
export const useCartStore('cart', {
actions: {
checkout() {
const authStore = useAuthStore();
if(authStore.user) throw new Error('请先登录');
// 调用订单接口...
},
},
});
8.注意事项
- 避免直接修改Store实例:使用Actions或$patch确保状态变更
- 性能优化:拆分高频变更状态到独立Store,减少渲染影响
- 合理设计Store:按业务功能划分Store,避免单一Store过于臃肿
- 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
:静态内容只渲染一次
<div v-once>永不更新的内容</div>
- v-memo
(Vue3.2+):依赖不变时跳过更新
<div v-memo="[value]">{{ value }}</div> <!-- 仅当value变化时更新 -->
v-show
:高频切换(CSS显示隐藏)v-if
:低频切换(销毁/重建组件)
2.组件设计优化
- 细粒度拆分:隔离高频更新组件
- 异步组件:延迟加载非关键组件
const Modal = defineAsyncComponet(() => import('./Modal.vue'));
3.状态管理优化
shallowRef/shalloReactive
:非深度响应式数据
const largeObj = shallowRef({ ... }) // 仅.value变化触发更新
- 避免大型响应式对象:解构为独立ref
- 使用markRaw跳过响应式转换
const staticData = markRaw({ ... }) // 不转换为响应式
3.资源与加载优化
1.代码分割
- 路由级懒加载(
Vue Router
)
{ path: '/dashboard', component: () => import('./Dashboard.vue') }
- 组件级懒加载(
defineAsyncComponent
) - 第三方库按需加载:
import { debounce } from 'lodash-es'; // 只引入所需函数
2.Tree Shaking支持
- 使用ES模块语法(ESM)
- 避免副作用代码:
pakage.json 中标记 "sideEffects": false
3.预加载关键资源
<!-- 预加载首屏关键组件 -->
<link rel="preload" as="script" href="/src/components/Critical.vue">
4.运行时性能优化
1.列表渲染优化
- 必须提供key:
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
- 虚拟滚动(vue-virtual-scroller)
<RecycleScroller :items="largeList" item-size="50">
<template #default="{ item }">{{ item.text }}</template>
</RecycleScroller>
- 避免v-for与v-if共用(优先用computed过滤数据)
2.计算与侦听优化
- computed缓存:替代模板内复杂表达式
- 避免深度监听大型对象:
watch(data, callback, { deep: false }) // 默认浅层监听
- watchEffect自动依赖追踪:
watchEffect(() => console.log(state.count)) // 自动收集依赖
3.事件处理优化
- 高频事件使用防抖/节流
import { debounce } from 'lodash-es';
methods: { search: debounce(fn, 300) }
5.架构级优化
1.服务端渲染(SSR)
- 使用Nuxt.js实现
npx nuxi init my-ssr-app
- 优势:提升首屏加载速度 & SEO
2.静态站点生成(SSG)
- 使用VitePress/VuePress:
npm init vitepress
- 预生成静态页面,适合内容型网站
3.CDN与缓存策略
- 静态资源添加Content Hash:
app.3a88b9e2.js # 文件名包含hash
- 设置长期缓存:
location /assets {
expires 1y;
add_header Cache-Control "public";
}
6.工具链优化
1.现代构建工具
- Vite:基于ESM的极速开发体验
npm create vite@lastest
- 生产构建优化:
// vite.config.js
export default {
build: {
minify: 'terser', // 代码压缩
brtliSize: true, // 压缩分析
chunkSizeWarningLimit: 1000 // 调整块大小警告
}
}
2.性能分析工具
Chorme DevTools Performance
面板Vue DevTools
性能追踪Lighthouse
性能评分
lighthouse http://localhost:5173 --view
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.虚拟滚动实现
<template>
<VirtualList :items="items" :item-size="50" height="300px">
<template #default="{ item }">
<ListItem :item="item" />
</template>
</VirtualList>
</template>
2.状态更新批处理
import { nextTick } from 'vue';
async function batchUpdate() {
state.a = 1;
state.b = 2;
await nextTick() // 等待一次更新
// DOM已更新
}
3.Web Worker处理CPU密集型任务
// main.js
const woker = new Worker('./worker.js');
worker.postMessage(data);
worker.onmessage = e => { state.result = e.data }
9.优化原则总结
- 量度优先:用
Lighthouse/Vue Devtools
定位瓶颈 - 渐进优化:优先解决最大性能瓶颈(如长列表/包体积)
- 平衡之道:避免过度优化牺牲可维护性
- 更新策略:
六、Vue2和Vue3的区别
1.架构设计区别
2.响应式系统升级
1.Vue的局限性
// 无法检测动态添加的属性
this.$set(this.obj, 'newProp', value);
// 无法监听数组索引发生变化
this.$set(this.arr, index, value);
2.Vue3的Proxy实现
const proxy = new Proxy(data, {
get(target, key) { /* 依赖收集 */ },
set(target, key, value) { /* 触发更新 */ }
})
- 优势
- 支持动态属性增删/数组索引修改
- 无需初始化深度遍历(惰性依赖追踪)
- 内存占用减少50%(基于基准测试)
3.Composition API vs Options API
1.Options API 痛点
export default {
data() {
return {
count: 0
}
},
methods: { increment() {...} },
computed: { double() {...} }
}
2.Composition API 解决方案
import { ref, computed } from 'vue';
export function useCounter() {
const count = ref(0);
const double = computed(() => count.value * 2);
function increment() { count.value++ }
return { count, double, increment }; // 逻辑聚合
}
- 核心优势:
- 逻辑复用(自定义Hook)
- 更好的TypeScript支持
- 代码组织更灵活(按功能而非选项)
4.性能优化对比
编译优化示例:
// Vue3 编译后的Patch Flags (二进制标记)
export function render() {
return (_openBlock(), _createBlock("div", null, [
_createVNode("span", null, "静态内容"), // 静态节点
_createVNode("span", { class: _ctx,dynamicClass }, null, 2 /* CLASS */)
]))
}
5.生命周期变化
使用示例:
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => console.log('组件挂载'))
onUnmounted(() => console.log('组件卸载'))
}
}
6.新特性与API
1.Fragment(碎片)
<!-- Vue3 支持多根节点 -->
<template>
<header>...</header>
<main>...</main>
<footer>...</footer>
</template>
2.Teleport(传送门)
<teleport to="#modal-container">
<div class="modal">模态框内容</div>
</teleport>
3.Suspense(异步组件)
<Suspense>
<template #default><AsyncComponent /></template>
<template #fallback><div>Loading...</div></template>
</Suspense>
4.自定义渲染器API
import { createRenderer } from 'vue';
const { render } = createRenderer({ /* 自定义节点操作 */ })
7.生态与工具链
8.迁移升级攻略
1.兼容方案
- @vue/compat库提供兼容模式(Vue2行为 + Vue3特性)
- 逐步替换废弃的API(eventBus -> mitt,Vue.extend -> defineComponent)
2.自动迁移工具
npm install -g @vue/compat
vue-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对比
2.高频面试题
1.SPA首屏加载优化有哪些方案?
- 路由懒加载 + 组件懒加载
- 资源预加载/预取
- CDN加速静态资源
- 开启Gzip/Brotli压缩
- 服务端渲染(SSR)
2.如何解决SPA的SEO问题?
- 预渲染(Prerender)
- 服务端渲染(Nustjs)
- 动态渲染(针对爬虫单独处理)
- 静态站点生成(SSG)
3.Vue Router的导航守卫执行顺序
全局 beforeEach -> 路由 beforeEnter -> 组件 beforeRouteEnter -> 全局 beforeResolve -> 全局 afterEach -> 组件 beforeRouteUpdate
4.如何处理权限路由?
// 动态添加路由
router.beforeEach(async (to) => {
if (!hasAuthInfo) await fetchUserPermissions();
if (to.meta.requiresAdmin && !isAdmin) return '/no-permission';
})
5.SPA如何保持登录状态?
- JWT存储于localStorage + 刷新Token机制
- 结合HttpOnly Cookie增强安全性
- Token过期自动跳转登录页
八、SSR
1.SSR核心概念与原理
1.服务端渲染 vs 客户端渲染
2.Vue SSR 工作原理
3.关键流程说明
- 服务端渲染:
renderToString()
生成静态HTML - 客户端激活:
createSSRApp().mount()
接管DOM添加事件 - 数据预取:在渲染前获取页面所需数据(避免客户端二次请求)
2.Nuxt.js 3 核心使用
1.项目结构与约定
├─ .nuxt/ # 构建生成
├─ components/ # 公共组件
├─ composables/ # 复用逻辑
├─ layouts/ # 布局组件
├─ middleware/ # 路由中间件
├─ pages/ # 自动路由(支持动态路由)
├─ plugins/ # 插件注册
├─ public/ # 静态资源
├─ server/ # API 路由
└─ nuxt.config.ts # 配置文件
2.服务端生命周期
// 服务端异步数据获取
useAsyncData('key', async () => {
const data = await $fetch('/api/data')
return data;
})
// 只在服务端执行
onServerPrefetch(async () => {
// 预取数据到Store
})
3.渲染模式配置
// nuxt.config.ts
export default defineNustConfig({
ssr: true, // 开启SST(默认)
// 或使用混合模式
routeRules: {
'/static': { prerender: true },
'/spa/**': { ssr: false }
}
});
3.数据获取与状态管理
1.数据预取策略
2.Pinia状态同步
// store/user.ts
export const useUserStore = defineStore('user', {
state: () => ({ token: null }),
actions: {
// Nuxt 特有钩子
async nustServerInit() {
this.token = await getTokenFormCookie();
}
}
});
// 客户端自动激活状态
4.性能优化策略
1.渲染层优化
- 组件缓存:
// nuxt.config.ts
export default {
render: {
componentCache: {
max: 1000,
maxAge: 1000 * 60 * 15 // 缓存15分钟
}
}
}
- 页面级缓存
// 使用 nitro 缓存
export default defineNitroConfig({
storage: {
redis: { driver: 'redis', url: 'redis://localhost:6379'}
},
routeRules: {
'/': { cache: { maxAge: 60 } } // 缓存首页60秒
}
})
2.资源加载优化
- 预加载关键资源
<head>
<link rel="preload" href="/main.css" as="style">
<link ref="modulepreload" href="/vendor.js">
</head>
- HTTP/2 服务端推送
Link </app.css>; rel=preload; as=style
2.流式渲染
// 替代 renderToString
const stream = renderToNodeStream(app);
stram.pipe(res, { end: false });
5.错误处理与调试
1.全局错误捕获
// 客户端错误
export default defineNustPlugin(nustApp => {
nustApp.vueApp.config.errorHandler = (err) => {
console.error('客户端错误:', err);
}
})
// 服务端错误(Nitro)
export default defineNitroPluign((nitroApp) => {
nitroApp.hooks.hook('error', (err) => {
logErrorToService(err);
})
})
2.Sentry集成
// nust.config.ts
modules: ['@nustjs/sentry'],
sentry: {
dsn: 'YOUR_DSN',
tracing: true // 性能监控
}
6.安全最佳实践
1.XSS防护
- 避免在服务端渲染中使用v-html
- 使用vue-basic-sanitize过滤用户内容
2.CSRF防护
// 使用 nitro server API
export default defineEventHandler(event => {
if (!isValidCSRF(event)) {
throw createError({ status: 403, message: 'Forbidden' })
}
return { data: '安全数据' }
})
3.CORS配置
// nuxt.config.ts
export default {
nitro: {
middleware: [
corsHander({
origin: ['http://yourdomain.com'],
methods: ['GET', 'POST']
})
]
}
}
7.高阶应用场景
1.混合渲染(Hydrid Rendering)
// nuxt.config.ts
export default {
routeRules: {
// 静态生成
'privacy': { prerender: true },
// 客户端渲染
'/dashboard/**': { ssr: false },
// 增量静态生成
'/products': { swr: 3600 }
}
}
2.边缘渲染(Edge-Side Renddering)
# 部署到边缘计算平台
npx nuxi build --preset=vercel-edge
3.微前端集成
// 在 Nuxt 中嵌入子应用
export default defineComponent({
async setup() {
const microApp = await loadMicroApp('react-subapp', '#container');
}
})
8.高频面试题
1.SSR的核心优势
- 提升首屏速度
- 更好的SEO
- 更稳定的用户体验
2.hydration过程可能出现的问题
- 客户端和服务端渲染的DOM结构不一致导致hydration失败
- 解决方案:
- 避免在
<template>
中使用随机数 - 确保服务端/客户端初始状态一致
- 用v-if替代v-show处理不可见元素
- 避免在
3.如何处理异步数据的服务端渲染?
- 使用
useAsyncData
或onServerPrefetch
在渲染前获取数据 - 通过
__NUXT__.state
注入到HTML
供客户端激活
4.如何优化高并发下的SSR性能?
- 组件级缓存+页面级缓存
- 流式渲染减少TTFB(首字节时间)
- 负载均衡+水平扩展服务器
5.Nuxt3相比Nuxt2的重大改进
- 基于Vite的极速HMR
- 支持混合渲染和增量静态生成
- Nitro引擎提供Serverless/Edge
- 更好的TypeScript集成
9.实战注意事项
1.避免全局副作用
// 错误示例:在服务端共享全局变量
let count = 0;
export const useCounter = () => ({ count: ++count })
// 正确:每个请求独立上下文
export const useCounter = () => {
const count = ref(0);
return { count };
}
2.环境区分处理
const runtimeConfig = useRuntimeConfig();
const apiBase = process.server ? runtimeConfig.apiSecret : runtimeConfig.public.apiBase;
3.性能监控指标
以上是Vue3面试题的进阶篇内容,如有错误欢迎评论区指正,后续还会更新Vue3原理篇。