Vue 高频知识点五十条

90 阅读15分钟

一、Vue2 & Vue3 基础与原理

1. Vue2 和 Vue3 的响应式原理有何区别?

答案

  • Vue2:使用 Object.defineProperty 劫持对象属性,仅支持对象属性的响应式,无法监听数组索引或对象属性的新增/删除。
  • Vue3:采用 Proxy 替代 Object.defineProperty,支持对整个对象/数组的监听,解决了 Vue2 的局限性(如数组索引变化、新增属性)。

纵向延伸

  • 性能优化Proxy 更高效,减少不必要的依赖追踪。
  • 应用场景:Vue3 更适合大型项目的数据响应式需求。

更深层次问题

  • 如何手动实现一个简化版的 Proxy 响应式系统?
  • Vue3 中如何监听 ref 的变化?

2. v-if 和 v-show 的区别是什么?

答案

  • v-if:条件为假时销毁元素,适合静态条件切换。
  • v-show:通过 display: none 控制可见性,适合频繁切换的动态条件。

纵向延伸

  • 性能影响v-show 更高效,但隐藏内容仍占用内存。
  • SEO 优化v-if 可避免隐藏内容被搜索引擎抓取。

更深层次问题

  • 如何结合 v-show 实现动态组件切换?
  • v-if 与 v-show 在 Vue3 中的性能差异?

3. Vue3 的 Composition API 与 Options API 的区别?

答案

  • Composition API:通过 setup() 函数组织逻辑,支持逻辑复用和更灵活的代码结构。
  • Options API:将逻辑分散在生命周期钩子中,适合小型项目。

纵向延伸

  • TypeScript 支持:Composition API 对 TypeScript 的类型推导更友好。
  • 代码组织:Composition API 更适合大型项目逻辑解耦。

更深层次问题

  • 如何在 setup 中访问 this
  • 如何在 Options API 中使用自定义 Hook?

二、Vue Router 路由管理

4. Vue Router 的两种路由模式有何区别?

答案

  • hash 模式:URL 中包含 #,兼容低版本浏览器,无需后端配置。
  • history 模式:URL 看似普通路径,需后端配置 index.html 作为入口。

纵向延伸

  • SEO 优化history 模式更友好,但需确保后端支持。
  • 应用场景:企业级项目常用 history 模式。

更深层次问题

  • 如何实现动态路由参数?
  • abstract 模式的适用场景?

5. 路由导航守卫有哪些类型?执行顺序是怎样的?

答案

  • 全局守卫beforeEachbeforeResolveafterEach
  • 路由独享守卫beforeEnter
  • 组件内守卫beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

纵向延伸

  • 权限控制:通过 beforeEach 检查用户登录状态。

  • 执行顺序

    beforeRouteLeave -> beforeEach -> beforeEnter -> beforeRouteUpdate -> beforeResolve -> afterEach
    

更深层次问题

  • 如何实现路由懒加载?
  • beforeRouteEnter 中如何访问组件实例?

6. 如何实现路由的动态加载?

答案

const Home = () => import('@/views/Home.vue');
const routes = [
  { path: '/home', component: Home }
];

纵向延伸

  • 性能优化:结合 webpack 的代码分割,减少首屏加载时间。
  • 应用场景:大型单页应用(SPA)。

更深层次问题

  • 如何实现按需加载?
  • 动态路由与静态路由的性能对比?

三、Pinia 状态管理

7. Pinia 与 Vuex 的核心区别是什么?

答案

特性PiniaVuex
语法风格基于 setup(),支持 Composition API传统 mutations/actions
模块化自动支持模块化需手动配置 namespaced
TypeScript原生支持需手动定义类型

纵向延伸

  • 开发体验:Pinia 简化了状态管理逻辑,减少冗余代码。
  • 官方推荐:Vue3 官方推荐 Pinia 作为首选状态管理方案。

更深层次问题

  • 如何实现 Pinia 的持久化存储?
  • Pinia 与 reactive 的性能对比?

8. Pinia 中如何定义和修改状态?

答案

// 定义
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++; }
  }
});

// 使用
const counter = useCounterStore();
counter.increment();

纵向延伸

  • 直接修改:可通过 store.count++ 直接修改状态,无需 mutations
  • 性能优化:避免频繁修改状态,减少不必要的渲染。

更深层次问题

  • 如何实现异步操作?
  • Pinia 的 watch 与 Vue 的 watch 有何不同?

9. Pinia 如何实现模块化?

答案
Pinia 默认支持模块化,通过 defineStore 分割不同功能模块:

// userStore.js
export const useUserStore = defineStore('user', {
  state: () => ({ name: 'John' })
});

纵向延伸

  • 命名规范:建议按业务划分模块(如 useAuthStore)。
  • 组合使用:多个模块可组合使用,避免全局污染。

更深层次问题

  • 如何实现模块间通信?
  • Pinia 模块与 Vue 组件的关联?

四、Axios 异步请求

10. Axios 的拦截器如何使用?

答案

  • 请求拦截

    axios.interceptors.request.use(config => {
      config.headers.Authorization = 'Bearer token';
      return config;
    });
    
  • 响应拦截

    axios.interceptors.response.use(res => res.data, err => {
      if (err.response.status === 401) logout();
      return Promise.reject(err);
    });
    

纵向延伸

  • 应用场景:添加认证头、错误统一处理。
  • 性能优化:避免重复请求,减少服务器压力。

更深层次问题

  • 如何取消请求?
  • Axios 与 Fetch API 的性能对比?

11. Axios 的 async/await 与 Promise 的区别?

答案

  • async/await:语法更简洁,适合多层嵌套请求。
  • Promise:链式调用,适合简单异步操作。

纵向延伸

  • 错误处理try/catch 捕获 async/await 错误,catch 处理 Promise 错误。
  • 应用场景:复杂业务逻辑推荐 async/await

更深层次问题

  • 如何实现请求重试?
  • Axios 与 Fetch 的兼容性差异?

12. 如何防止重复请求?

答案

  • 拦截器取消请求

    const CancelToken = axios.CancelToken;
    let cancel;
    axios.get('/api/data', {
      cancelToken: new CancelToken(c => cancel = c)
    });
    // 取消请求
    cancel('Operation canceled');
    

纵向延伸

  • 应用场景:搜索输入框的防抖请求。
  • 性能优化:减少无效请求,提升用户体验。

更深层次问题

  • 如何实现全局请求拦截?
  • Axios 与 Vue 的响应式结合?

五、综合应用与场景问题

13. 如何实现 Vue3 的组件懒加载?

答案

const LazyComponent = defineAsyncComponent(() => import('@/components/Lazy.vue'));

纵向延伸

  • 性能优化:按需加载组件,减少首屏加载时间。
  • 应用场景:大型项目或低带宽环境。

更深层次问题

  • 如何结合 Vue Router 实现路由懒加载?
  • 懒加载与异步组件的生命周期?

14. Vue3 中如何实现组件通信?

答案

  1. Props/Events:父子组件通信。
  2. VModel:双向绑定。
  3. Provide/Inject:跨层级通信。
  4. Pinia:全局状态共享。

纵向延伸

  • 最佳实践:小型项目用 props/events,大型项目用 Pinia。
  • 性能影响:避免过度使用 provide/inject 导致依赖混乱。

更深层次问题

  • 如何实现跨组件事件总线?
  • Vue3 中 eventBus 的替代方案?

15. Vue3 的 keep-alive 如何工作?

答案

  • 缓存组件

    <keep-alive>
      <component :is="currentComponent" />
    </keep-alive>
    
  • 生命周期钩子activated/deactivated

纵向延伸

  • 应用场景:表单草稿保存、动态组件切换。
  • 性能优化:避免缓存过多组件,占用内存。

更深层次问题

  • 如何动态控制缓存?
  • keep-alive 与 v-show 的性能对比?

六、性能优化与高级特性

16. Vue3 的 reactive 与 ref 有何区别?

答案

  • reactive:用于对象/数组的响应式,返回代理对象。
  • ref:用于基本类型的响应式,返回包含 value 的对象。

纵向延伸

  • 应用场景:对象用 reactive,数字/字符串用 ref
  • 性能优化:避免过度使用 reactive,减少代理开销。

更深层次问题

  • 如何实现嵌套 reactive
  • shallowReactive 的用途?

17. Vue3 的 watchEffect 与 watch 的区别?

答案

  • watchEffect:自动追踪依赖,立即执行并响应变化。
  • watch:手动指定依赖,适合精确控制。

纵向延伸

  • 性能影响watchEffect 可能触发多余执行,需谨慎使用。
  • 应用场景:复杂依赖用 watchEffect,简单监听用 watch

更深层次问题

  • 如何停止 watchEffect
  • watch 与 computed 的性能对比?

18. Vue3 的 Suspense 组件如何使用?

答案

<Suspense>
  <template #default>
    <AsyncComponent />
  </template>
  <template #fallback>
    <div>Loading...</div>
  </template>
</Suspense>

纵向延伸

  • 应用场景:异步组件加载时显示加载状态。
  • 性能优化:减少白屏时间,提升用户体验。

更深层次问题

  • 如何实现多层 Suspense
  • Suspense 与 async/await 的结合?

七、Vue Router 高级用法

19. 如何实现路由的动态参数传递?

答案

// 定义动态路由
{ path: '/user/:id', component: User }

// 传递参数
router.push({ path: '/user/123' });

// 获取参数
const userId = $route.params.id;

纵向延伸

  • 正则匹配:通过 path: '/user/:id(\d+)' 限制参数格式。
  • 应用场景:详情页、编辑页。

更深层次问题

  • 如何实现参数变化的监听?
  • 动态路由与静态路由的性能差异?

20. Vue Router 的 scrollBehavior 如何工作?

答案

const router = new VueRouter({
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) return savedPosition;
    return { x: 0, y: 0 };
  }
});

纵向延伸

  • 应用场景:页面跳转后滚动到顶部。
  • 兼容性:仅支持 history 模式。

更深层次问题

  • 如何实现平滑滚动?
  • scrollBehavior 与 window.scrollTo 的对比?

21. Vue Router 的 beforeRouteEnter 如何获取组件实例?

答案

beforeRouteEnter(to, from, next) {
  next(vm => {
    vm.fetchData(); // 访问组件实例
  });
}

纵向延伸

  • 生命周期限制beforeRouteEnter 中无法直接访问 this
  • 应用场景:数据预加载。

更深层次问题

  • 如何在 beforeRouteLeave 中阻止导航?
  • next(false) 的使用场景?

八、Pinia 与 Vue3 深度整合

22. Pinia 如何与 Vue3 的 setup 结合使用?

答案

import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({ name: 'John' }),
  actions: {
    updateName(newName) { this.name = newName; }
  }
});

纵向延伸

  • 响应式集成:Pinia 的 state 自动响应式,无需额外处理。
  • 开发体验:Composition API 风格代码更易维护。

更深层次问题

  • 如何实现 Pinia 的模块化?
  • Pinia 与 reactive 的性能对比?

23. Pinia 如何实现异步操作?

答案

actions: {
  async fetchUser(id) {
    const response = await axios.get(`/api/user/${id}`);
    this.user = response.data;
  }
}

纵向延伸

  • 错误处理:使用 try/catch 捕获异常。
  • 应用场景:数据拉取、表单提交。

更深层次问题

  • 如何实现请求重试?
  • Pinia 与 Axios 的拦截器结合?

24. Pinia 的 watch 与 Vue 的 watch 有何不同?

答案

  • Pinia 的 watch:监视 store 中的状态变化。
  • Vue 的 watch:监视组件中的响应式数据。

纵向延伸

  • 性能影响:Pinia 的 watch 更适合全局状态监控。
  • 应用场景:数据变化时触发副作用。

更深层次问题

  • 如何实现深度监听?
  • Pinia 的 watch 与 computed 的对比?

九、Axios 与 Vue3 结合实践

25. 如何在 Vue3 中封装 Axios 请求?

答案

import axios from 'axios';

const apiClient = axios.create({
  baseURL: '/api',
  timeout: 5000
});

export default {
  getUser(id) {
    return apiClient.get(`/user/${id}`);
  }
};

纵向延伸

  • 模块化:按业务划分 API 接口(如 userApi.js)。
  • 错误处理:统一拦截错误并提示用户。

更深层次问题

  • 如何实现接口权限校验?
  • Axios 与 Vue 的响应式结合?

26. Axios 的 CancelToken 如何取消请求?

答案

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/api/data', {
  cancelToken: new CancelToken(c => cancel = c)
});

// 取消请求
cancel('Operation canceled');

纵向延伸

  • 应用场景:搜索输入框的防抖请求。
  • 性能优化:减少无效请求,提升用户体验。

更深层次问题

  • 如何实现全局请求拦截?
  • Axios 与 Fetch API 的兼容性差异?

27. 如何实现 Axios 的请求重试?

答案

axios.interceptors.response.use(res => res, err => {
  const config = err.config;
  if (!config || !config.retry) return Promise.reject(err);
  config.retryCount = config.retryCount || 0;
  if (config.retryCount >= config.retry) return Promise.reject(err);
  config.retryCount++;
  return new Promise(resolve => setTimeout(() => resolve(axios(config)), 1000));
});

纵向延伸

  • 应用场景:网络不稳定时自动重试。
  • 性能优化:避免无限重试,设置最大重试次数。

更深层次问题

  • 如何实现指数退避算法?
  • Axios 与 Vue 的响应式结合?

十、Vue3 与 Pinia 的性能优化

28. Vue3 的 shallowReactive 和 shallowRef 有何用途?

答案

  • shallowReactive:仅响应式第一层属性,适合大型对象。
  • shallowRef:仅响应式 value,适合引用类型。

纵向延伸

  • 性能优化:减少深层响应式开销,提升渲染效率。
  • 应用场景:大型数据集合或第三方库对象。

更深层次问题

  • 如何实现深层响应式?
  • shallowReactive 与 reactive 的性能对比?

29. Pinia 如何实现状态持久化?

答案

import { defineStore } from 'pinia';
import { useLocalStorage } from '@vueuse/core';

export const useUserStore = defineStore('user', {
  state: () => ({
    name: useLocalStorage('user.name', 'John')
  })
});

纵向延伸

  • 第三方库:结合 localStorage 或 IndexedDB
  • 应用场景:用户偏好存储。

更深层次问题

  • 如何加密存储数据?
  • Pinia 与 Vue 的响应式结合?

30. Vue3 的 customRef 如何自定义响应式?

答案

function debounceRef(value, delay) {
  let timer;
  return customRef((track, trigger) => ({
    get() {
      track();
      return value;
    },
    set(newValue) {
      clearTimeout(timer);
      timer = setTimeout(() => {
        value = newValue;
        trigger();
      }, delay);
    }
  }));
}

纵向延伸

  • 应用场景:搜索输入框的防抖。
  • 性能优化:减少不必要的更新。

更深层次问题

  • 如何实现节流?
  • customRef 与 watch 的对比?

十一、Vue Router 与 Pinia 的结合

31. 如何在 Vue Router 中使用 Pinia 状态?

答案

// 在组件中
import { useUserStore } from '@/stores/user';

export default {
  setup() {
    const userStore = useUserStore();
    return { userStore };
  }
};

纵向延伸

  • 权限控制:结合 beforeEach 检查用户登录状态。
  • 应用场景:动态路由权限管理。

更深层次问题

  • 如何实现路由懒加载?
  • Pinia 与 Vue Router 的生命周期钩子结合?

32. Vue Router 如何实现动态路由权限管理?

答案

router.beforeEach(async (to, from, next) => {
  const userStore = useUserStore();
  if (to.meta.requiresAuth && !userStore.isLoggedIn) {
    next('/login');
  } else {
    next();
  }
});

纵向延伸

  • 动态路由:根据用户角色动态加载路由。
  • 应用场景:企业级后台管理系统。

更深层次问题

  • 如何实现路由缓存?
  • 动态路由与静态路由的性能对比?

33. 如何在 Pinia 中存储和读取 Vue Router 的状态?

答案

// 存储
const router = useRouter();
piniaStore.route = router.currentRoute.value;

// 读取
const currentRoute = piniaStore.route;

纵向延伸

  • 应用场景:跨组件共享路由信息。
  • 性能优化:避免频繁访问 currentRoute

更深层次问题

  • 如何实现路由信息持久化?
  • Pinia 与 Vue Router 的生命周期钩子结合?

十二、Vue3 与 Axios 的高级用法

34. 如何在 Vue3 中实现 Axios 的全局错误处理?

答案

axios.interceptors.response.use(
  res => res,
  err => {
    if (err.response?.status === 401) logout();
    return Promise.reject(err);
  }
);

纵向延伸

  • 应用场景:统一错误提示和重定向。
  • 性能优化:避免重复错误处理逻辑。

更深层次问题

  • 如何实现错误日志记录?
  • Axios 与 Vue 的响应式结合?

35. Axios 的 transformRequest 和 transformResponse 有何用途?

答案

  • transformRequest:修改请求数据(如 JSON 转换)。
  • transformResponse:修改响应数据(如错误码处理)。

纵向延伸

  • 应用场景:统一数据格式转换。
  • 性能优化:减少业务代码中的数据处理逻辑。

更深层次问题

  • 如何实现数据脱敏?
  • Axios 与 Vue 的响应式结合?

36. 如何在 Vue3 中实现 Axios 的并发请求?

答案

const [user, posts] = await Promise.all([
  axios.get('/api/user'),
  axios.get('/api/posts')
]);

纵向延伸

  • 应用场景:同时获取多个资源。
  • 性能优化:减少请求次数,提升加载速度。

更深层次问题

  • 如何处理部分失败?
  • Axios 与 Vue 的响应式结合?

十三、Vue3 与 Pinia 的深度整合

37. Pinia 如何实现模块间的通信?

答案

// 在 storeA.js 中
export const useStoreA = defineStore('a', {
  actions: {
    updateStoreB() {
      const storeB = useStoreB();
      storeB.updateValue();
    }
  }
});

纵向延伸

  • 应用场景:跨模块状态共享。
  • 性能优化:避免过度依赖,保持模块独立。

更深层次问题

  • 如何实现模块间事件总线?
  • Pinia 与 Vue 的响应式结合?

38. Pinia 的 storeToRefs 有何作用?

答案

  • 作用:解构 store 的 state 时保持响应式。

    const { count } = storeToRefs(useCounterStore());
    

纵向延伸

  • 应用场景:避免 ref 丢失响应式。
  • 性能优化:减少不必要的解构。

更深层次问题

  • 如何实现嵌套 storeToRefs
  • storeToRefs 与 reactive 的对比?

39. Pinia 如何实现异步初始化?

答案

export const useUserStore = defineStore('user', {
  state: () => ({ user: null }),
  actions: {
    async init() {
      this.user = await fetchUser();
    }
  }
});

纵向延伸

  • 应用场景:用户登录后初始化数据。
  • 性能优化:避免阻塞首屏渲染。

更深层次问题

  • 如何实现自动初始化?
  • Pinia 与 Vue Router 的生命周期钩子结合?

十四、Vue3 与 Vue Router 的性能优化

40. Vue3 的 v-memo 指令如何使用?

答案

<div v-memo="[count]"> {{ count }} </div>

纵向延伸

  • 作用:跳过不需要的子树更新,提升性能。
  • 应用场景:大型列表或复杂组件。

更深层次问题

  • 如何优化 v-memo 的依赖项?
  • v-memo 与 v-show 的性能对比?

41. Vue3 的 Fragment 是什么?

答案

  • 作用:允许组件返回多个根节点。

    <template>
      <h1>Title</h1>
      <p>Content</p>
    </template>
    

纵向延伸

  • 应用场景:减少不必要的嵌套。
  • 性能优化:避免额外的 DOM 节点。

更深层次问题

  • 如何实现多个根节点的条件渲染?
  • Fragment 与 v-show 的性能对比?

42. Vue3 的 Teleport 如何工作?

答案

<Teleport to="#modal">
  <div class="modal">Modal Content</div>
</Teleport>

纵向延伸

  • 应用场景:模态框、全局提示。
  • 性能优化:避免组件层级嵌套。

更深层次问题

  • 如何实现动态 to
  • Teleport 与 v-show 的性能对比?

十五、Vue3 与 Axios 的深度整合

43. 如何在 Vue3 中实现 Axios 的全局请求头?

答案

axios.defaults.headers.common['Authorization'] = 'Bearer token';

纵向延伸

  • 应用场景:认证请求头。
  • 性能优化:避免重复设置。

更深层次问题

  • 如何动态更新请求头?
  • Axios 与 Vue 的响应式结合?

44. Axios 的 transformRequest 和 transformResponse 有何用途?

答案

  • transformRequest:修改请求数据(如 JSON 转换)。
  • transformResponse:修改响应数据(如错误码处理)。

纵向延伸

  • 应用场景:统一数据格式转换。
  • 性能优化:减少业务代码中的数据处理逻辑。

更深层次问题

  • 如何实现数据脱敏?
  • Axios 与 Vue 的响应式结合?

45. 如何在 Vue3 中实现 Axios 的并发请求?

答案

const [user, posts] = await Promise.all([
  axios.get('/api/user'),
  axios.get('/api/posts')
]);

纵向延伸

  • 应用场景:同时获取多个资源。
  • 性能优化:减少请求次数,提升加载速度。

更深层次问题

  • 如何处理部分失败?
  • Axios 与 Vue 的响应式结合?

十六、Vue3 与 Pinia 的性能优化

46. Pinia 的 storeToRefs 有何作用?

答案

  • 作用:解构 store 的 state 时保持响应式。

    const { count } = storeToRefs(useCounterStore());
    

纵向延伸

  • 应用场景:避免 ref 丢失响应式。
  • 性能优化:减少不必要的解构。

更深层次问题

  • 如何实现嵌套 storeToRefs
  • storeToRefs 与 reactive 的对比?

47. Pinia 如何实现异步初始化?

答案

export const useUserStore = defineStore('user', {
  state: () => ({ user: null }),
  actions: {
    async init() {
      this.user = await fetchUser();
    }
  }
});

纵向延伸

  • 应用场景:用户登录后初始化数据。
  • 性能优化:避免阻塞首屏渲染。

更深层次问题

  • 如何实现自动初始化?
  • Pinia 与 Vue Router 的生命周期钩子结合?

48. Pinia 的 watch 与 Vue 的 watch 有何不同?

答案

  • Pinia 的 watch:监视 store 中的状态变化。
  • Vue 的 watch:监视组件中的响应式数据。

纵向延伸

  • 性能影响:Pinia 的 watch 更适合全局状态监控。
  • 应用场景:数据变化时触发副作用。

更深层次问题

  • 如何实现深度监听?
  • Pinia 的 watch 与 computed 的对比?

十七、Vue3 与 Vue Router 的性能优化

49. Vue3 的 v-memo 指令如何使用?

答案

<div v-memo="[count]"> {{ count }} </div>

纵向延伸

  • 作用:跳过不需要的子树更新,提升性能。
  • 应用场景:大型列表或复杂组件。

更深层次问题

  • 如何优化 v-memo 的依赖项?
  • v-memo 与 v-show 的性能对比?

50. Vue3 的 Fragment 是什么?

答案

  • 作用:允许组件返回多个根节点。

    <template>
      <h1>Title</h1>
      <p>Content</p>
    </template>
    

纵向延伸

  • 应用场景:减少不必要的嵌套。
  • 性能优化:避免额外的 DOM 节点。

更深层次问题

  • 如何实现多个根节点的条件渲染?
  • Fragment 与 v-show 的性能对比?