《github 加星 Taimili.com 艾米莉 》 2026前端面试题-Vue3进阶篇

18 阅读10分钟

Vue进阶

一、keep-alive

1.核心作用和使用场景

1.作用
  • 缓存组件实例:避免重复销毁和创建,保留组件状态(如DOM结构、响应式数据、事件监听
  • 提升性能:适用于需要频繁切换但状态需保留的组件(如Tab页、表单填写页
Taimili 艾米莉 ( 一款专业的 GitHub star 管理和github 加星涨星工具taimili.com )

艾米莉 是一款优雅便捷的 GitHub star 管理和github 加星 涨星工具,基于 PHP & javascript 构建, 能对github star fork follow watch 刷星管理和提升,最适合github 的深度用户

WX20251021-210346@2x.png

2.使用方式
js
 体验AI代码助手
 代码解读
复制代码
<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选项),仅缓存匹配的组件
  • 支持字符串、正则、数组
js
 体验AI代码助手
 代码解读
复制代码
<!-- 缓存以 "Test" 开头的组件 -->
<keep-alive :include="/^Test/">  
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(响应式变量)
js
 体验AI代码助手
 代码解读
复制代码
<keep-alive :include="cachedComponents">
  • 方案2:通过key强制重新渲染(改变key会销毁旧实例)
js
 体验AI代码助手
 代码解读
复制代码
<component :is="currentComponent" :key="componentKey">
3.keep-alive如何结合路由使用
  • 搭配router-view
js
 体验AI代码助手
 代码解读
复制代码
<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字段标记需缓存的页面
js
 体验AI代码助手
 代码解读
复制代码
{ path: '/home', component: Home, meta: { keepAlive: true } }
4.缓存组件如何更新数据
  • onActivated中刷新数据
js
 体验AI代码助手
 代码解读
复制代码
onActivated(() => {
  fetchData(); // 重新请求数据
});
5.max属性的作用及淘汰策略
  • 作用:避免内存无限增长,限制最大缓存实例
  • 淘汰策略:LRU(最近最少使用),优先移除最久未被访问的实例

5.注意事项

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

6.实战实例

js
 体验AI代码助手
 代码解读
复制代码
<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推荐方式)
js
 体验AI代码助手
 代码解读
复制代码
import { defineAsyncComponent } from 'vue';
const AsyncCom = defineAsyncComponent(() => import('./MyComponent.vue'));
  • 动态import()语法(结合构建工具如Webpack/Vite实现代码分割)
js
 体验AI代码助手
 代码解读
复制代码
const AsyncComp = defineAsyncComponent({
    loader: () => import('./MyComponent.vue'),
    loadingComponent: loadingSpinner,  // 加载中组件
    errorComponent: ErrorDisplay,      // 错误组件
    delay: 1000,                       // 延迟显示loading(防闪烁)
    timeout,                           // 超时时间        
})
2.Suspense组件
  • 统一管理异步组件(如异步组件或异步setup函数):
js
 体验AI代码助手
 代码解读
复制代码
<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中捕获错误并重试
js
 体验AI代码助手
 代码解读
复制代码
const Async = defineAsyncComponent({
    loader: () => import('./MyComponent.vue')
        .catch(() => {
            // 重试逻辑
            return retryImport();
        })
})
5.异步组件在路由懒加载中的应用
  • Vue Router配置
js
 体验AI代码助手
 代码解读
复制代码
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魔法注释标记非关键资源
js
 体验AI代码助手
 代码解读
复制代码
() => import(/* webpackPrefetch: true */ './MyComponent.vue')
  • 懒加载阈值:结合路由或用户行为预测延迟加载组件

4.注意事项

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

5.实战代码实例

js
 体验AI代码助手
 代码解读
复制代码
// 异步组件定义
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.应用场景

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

三、Vue-Router

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

1.创建路由实例
js
 体验AI代码助手
 代码解读
复制代码
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
    history: createWebHistory(),  // 或 createWebHashHistory
    routes: [...]
});
2.组合式API支持
  • useRouter() :获取路由实例(替代this.$router
  • useRoute() :获取当前路由对象(替代this.$route

2.路由配置与核心概念

1.动态路由
js
 体验AI代码助手
 代码解读
复制代码
{ path: '/user/:id', component: User };
// 获取参数:route.params.id
2.嵌套路由
js
 体验AI代码助手
 代码解读
复制代码
{
    path: '/parent',
    component: Parent,
    children: [
        { path: 'child', component: Child }
    ]
}
3.命名路由与编程式导航
js
 体验AI代码助手
 代码解读
复制代码
router.push({ name: 'user', params: { id: 1 } });
4.路由模式
  • createWebHistory():History模式(需服务器支持)
  • createWebHashHistory():Hash模式
  • createMemoryHistory():SSR或测试环境
5.重定向与别名
js
 体验AI代码助手
 代码解读
复制代码
{ path: '/home', redirect: '/' }
{ path: '/', alias: 'home' }

3.导航守卫

1.全局守卫
  • router.beforeEach((to, from, next) => { ... })
  • router.afterEach((to, from) => { ... })
  • router.beforeResolve()
2.路由独享守卫
js
 体验AI代码助手
 代码解读
复制代码
{
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from, next) => { ... }
}
3.组件内守卫
  • onBeforeRouteUpdate:路由参数变化
  • onBeforeRouteLeave:离开组件前
js
 体验AI代码助手
 代码解读
复制代码
import { onBeforeRouteLeave } from 'vue-router';
export default {
    setup() {
        onBeforeRouteLeave((to, from, next) => {
            // 清理逻辑
            next();
        });
    }
};

4.高级特性与最佳实践

1.路由懒加载
js
 体验AI代码助手
 代码解读
复制代码
const User = () => import('./User.vue');
const User = defineAsyncComponent(() => import('./User.vue'));
2.路由元信息(meta)
js
 体验AI代码助手
 代码解读
复制代码
{ path: '/profile', meta: { requireAuth: true } }
// 在导航守卫中访问:to.meta.requiresAuth
3.动态路由
  • 添加路由router.addRoute({ path: '/new', component: New })
  • 删除路由router.removeRoute('route-name')
4.路由组件传参
js
 体验AI代码助手
 代码解读
复制代码
{ path: '/user/:id', component: User, props: true }
// 组件通过props:['id'] 接收
5.滚动行为控制
js
 体验AI代码助手
 代码解读
复制代码
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.如何实现路由权限控制
  • 全局守卫 + 元信息
js
 体验AI代码助手
 代码解读
复制代码
router.beforeEach((to, from, next) => {
    if(to.meta.requireAuth && !isAuthenticated) next('/login');
    else next();
});
3.如何处理动态路由加载顺序问题
  • router.isReady():确保初始路由解析完成再挂载应用
js
 体验AI代码助手
 代码解读
复制代码
router.isReady().then(() => app.mount('#app'));
4.如何捕获导航错误
js
 体验AI代码助手
 代码解读
复制代码
router.onError((error) => {
    console.error('导航错误', error);
});
5.路由组件如何复用并响应参数变化
  • onBeforeRouteUpdate:监听路由参数变化
js
 体验AI代码助手
 代码解读
复制代码
onBeforeRouteUpdate((to, form, next) => {
    fetchData(to.params.id);
    next();
})

6.实战场景示例

js
 体验AI代码助手
 代码解读
复制代码
// 动态添加路由(权限控制)
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.注意事项

  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.工作流程
js
 体验AI代码助手
 代码解读
复制代码
组件 -> dispatch(Action) -> Action -> commit(Mutation) -> Mutation -> 修改State -> 更新视图

3.Vue4.x对Vue3的支持

  • 兼容Vue3的Composition API,但核心API与Vuex 3.x一致
  • 通过useStore替代this.$store(组合式API中)
js
 体验AI代码助手
 代码解读
复制代码
import { useStore } from 'vuex';
export default {
    setup() {
        const store = useStore();
        return { store };
    }
};
2.核心API与使用

1.定义Store

js
 体验AI代码助手
 代码解读
复制代码
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

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

3.辅助函数

  • mapState / mapGetters:映射到计算属性
  • mapMutation / MapActions:映射到方法
js
 体验AI代码助手
 代码解读
复制代码
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
    computed: {
        ...mapState(['count']),
        ...mapGetters(['doubleCount'])
    },
    methods: {
        ...mapMutations(['increment']),
        ...mapActions(['asyncIncrement'])
    }
};
3.模块化与命名空间

1.模块定义

js
 体验AI代码助手
 代码解读
复制代码
const moduleA = {
    namespaced: true, // 启用命名空间
    state: { ... },
    mutation: { ... },
    action: { ... }
};
const store = createStore({
    modules: { a: moduleA }
});

2.命名空间访问

  • 直接访问store.state.a.moduleData
  • 辅助函数
js
 体验AI代码助手
 代码解读
复制代码
...mapActions('a',['moduleAction']),
// 或通过createNamespacedHelpers
const { mapActions } = createNamespacedHelpers('a');

3.模块的局部上下文

  • Root State:在模块的Action中通过rootState访问全局状态
  • Root Commit:在模块Actions中通过{ root: true }提交全局Mutation
js
 体验AI代码助手
 代码解读
复制代码
actions: {
    localAction({ commit, dispatch, rootState }) {
        commit('localMutation');
        dispatch('gloabalAction', null, { root: true });
    }
}
4.高级特性与最佳实践

1.严格模式

js
 体验AI代码助手
 代码解读
复制代码
const store = createStore({ strict: true });
// 直接修改state会抛出错误(仅限开发环境)

2.插件开发

  • 订阅Mutations
js
 体验AI代码助手
 代码解读
复制代码
store.subscribe((mutation, state) => {
    console.log('Mutation:', mutation.type);
});
  • 持久化插件(如结合localStorage)
js
 体验AI代码助手
 代码解读
复制代码
const persistPlugin = (store) => {
    store.subscribe((mutation, state) => {
        localStorage.setItem('vuex-state', JSON.stringify(state));
    });
};

3.动态注册模块

js
 体验AI代码助手
 代码解读
复制代码
store.registerModule('dynamicModule', { ... });
store.unregisterModule('dynamicModule', { ... });