引言💭
总结最近面试中碰到的Vue考点。
一、Vue 3 的常用 API
ref
和 reactive
ref
:用于创建基本数据类型(如字符串、数字、布尔值等)的响应式引用,通过 .value
访问和修改数据。
const count = ref(0); // 基本类型响应式数据
reactive
:用于创建对象或数组的响应式数据,直接对对象进行响应式代理,可直接通过属性名访问和修改。
const user = reactive({ name: 'Alice', age: 25 }); // 对象响应式数据
computed
- 用于创建计算属性,基于依赖的响应式数据进行缓存,仅在依赖数据变化时重新计算。
const doubleCount = computed(() => count.value * 2); // 计算属性示例
watch
- 用于监听响应式数据的变化,执行副作用操作(如异步请求、数据存储)。
watch(count, (newVal, oldVal) => { /* 数据变化时执行 */ }); // 监听示例
生命周期函数(组合式 API)
onMounted
:组件挂载完成后执行(替代 Vue 2 的 mounted
)。
onUpdated
:组件更新完成后执行(替代 Vue 2 的 updated
)。
onUnmounted
:组件卸载后执行(替代 Vue 2 的 destroyed
)。
defineComponent
- 用于定义组件,支持组合式 API 和 TypeScript 类型推导,增强可读性和类型安全。
import { defineComponent } from 'vue';
export default defineComponent({ /* 组件配置 */ });
provide
和 inject
- 跨层级组件通信方案:父组件通过
provide
提供数据,子组件通过 inject
注入获取。
// 父组件
provide('theme', 'dark');
// 子组件
const theme = inject('theme');
nextTick
- 在 DOM 更新后执行回调,确保获取更新后的 DOM 状态。
this.$nextTick(() => { /* DOM 更新后操作 */ });
useContext
- 获取当前组件的上下文,适用于函数式组件中访问 Vue 上下文信息。
二、ref
和 reactive
的区别
特性 | ref | reactive |
---|
适用类型 | 基本数据类型(string/number等) | 对象/数组 |
访问方式 | 通过 .value 访问 | 直接通过属性名访问 |
示例 | const num = ref(10); | const obj = reactive({ a: 1 }); |
三、computed
和 watch
的区别
特性 | computed | watch |
---|
核心作用 | 缓存计算结果,返回衍生数据 | 监听数据变化,执行副作用 |
触发时机 | 依赖数据变化时自动执行 | 监听数据变化时手动触发 |
适用场景 | 表单校验、动态标题等 | API 请求、数据提交等异步操作 |
四、Vue 2 的 mixin
和 Vue 3 的 hooks
的对比
特性 | mixin (Vue 2) | hooks (Vue 3) |
---|
逻辑复用 | 通过混入组件选项实现 | 通过组合式函数实现 |
命名冲突 | 可能引发冲突(共享组件选项) | 按函数作用域隔离,无冲突 |
维护性 | 大型项目中逻辑复杂难追踪 | 按功能拆分,可组合性强 |
五、v-if
和 v-for
的使用及 key
的作用
v-if
:条件渲染元素,条件为假时从 DOM 中移除元素,适合不频繁切换场景。
v-for
:循环渲染列表,需搭配唯一 key
(标识节点唯一性),提升虚拟 DOM Diff 效率。
<ul>
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
</ul>
六、Vue 3 组件生命周期及替代 API
Vue 2 生命周期 | Vue 3 组合式 API | 触发时机 |
---|
mounted | onMounted | 组件挂载到 DOM 后 |
updated | onUpdated | 组件数据更新并渲染后 |
beforeDestroy | onBeforeUnmount | 组件卸载前 |
destroyed | onUnmounted | 组件卸载后 |
七、Vue 2 与 Vue 3 的核心区别
特性 | Vue 2 | Vue 3 |
---|
响应式原理 | Object.defineProperty (不支持数组索引/嵌套对象) | Proxy (支持数组/嵌套对象,性能更优) |
API 风格 | 选项式(data /methods 等) | 组合式(setup +Hook,逻辑复用性强) |
TypeScript 支持 | 需额外配置 | 内置类型推导,原生支持 TS |
状态管理 | 官方推荐 Vuex | 官方推荐 Pinia(API 更简洁) |
虚拟 DOM 性能 | 中等优化 | 更快的 Diff 算法,大型应用性能提升 |
八、Vue 2 与 Vue 3 响应式系统的区别
- Vue 2:基于
Object.defineProperty
,需遍历对象属性,无法检测数组索引变更和嵌套对象深层变化。
- Vue 3:基于
Proxy
,直接代理整个对象,支持数组/嵌套对象的响应式追踪,性能更高。
九、Vue 组件通信方式
1. 父子组件通信
<!-- 父组件 -->
<child-component :message="parentMsg" />
// 子组件
this.$emit('update', childMsg);
2. 跨层级通信
provide/inject
:祖先组件提供数据,后代组件注入获取(适用于多层嵌套)。
- 状态管理库:使用 Vuex/Pinia 管理全局状态(适用于复杂场景)。
3. 兄弟组件通信
- 通过共同父组件中转数据,或使用全局事件总线(Vue 3 不推荐)。
十、Vuex 与 Pinia 的区别
特性 | Vuex | Pinia |
---|
适用版本 | Vue 2.x | Vue 3+ |
API 风格 | 选项式(mutations /actions ) | 组合式(函数式,支持 Hook) |
TypeScript | 需手动声明类型 | 内置类型推导,TS 友好 |
状态修改 | 需通过 commit /dispatch | 直接修改响应式状态 |
持久化 | 需手动实现 | 支持插件(pinia-plugin-persistedstate ) |
十一、选项式 API 和组合式 API 的区别
特性 | 选项式 API | 组合式 API |
---|
逻辑组织 | 按组件选项(data /methods )组织 | 按功能函数(setup +Hook)组织 |
逻辑复用 | 通过 mixin 实现 | 通过 hooks 函数实现 |
可维护性 | 大型项目中逻辑可能碎片化 | 按功能拆分,可维护性更高 |
适用场景 | 中小型项目,快速上手 | 复杂/大型项目,逻辑复用需求高 |
十二、v-show
和 v-if
的区别
特性 | v-show | v-if |
---|
渲染机制 | 通过 display: none 控制显隐 | 条件为假时完全移除 DOM元素 |
性能 | 切换频繁时性能更优(无需销毁重建) | 初次渲染性能较低(涉及 DOM 销毁) |
适用场景 | 高频切换(如按钮显隐) | 低频切换(如权限控制) |
十三、虚拟 DOM 与 Diff 算法
- 虚拟 DOM:用 JavaScript 对象模拟真实 DOM 结构,数据变更时先更新虚拟树,再批量同步到真实 DOM,减少直接操作 DOM 的开销。
- Diff 算法:对比新旧虚拟 DOM 树,仅更新变化的节点,通过
key
标识节点唯一性,提升更新效率。
十四、v-bind
和 v-model
v-bind
:单向绑定 HTML 属性或组件特性。
<a :href="url">链接</a> <!-- 动态绑定 href 属性 -->
v-model
:双向绑定表单元素值(如 input
/textarea
),自动同步数据与视图。
<input v-model="text" /> <!-- 双向绑定输入框值 -->
十五、Vue 3 的响应式劫持(Proxy)
- Vue 3 使用
Proxy
替代 Vue 2 的 Object.defineProperty
,实现对对象的响应式代理。
- 优势:
- 支持数组索引变更和嵌套对象深层响应式。
- 性能更优,拦截操作更全面(如属性删除、数组长度变化)。
十六、Vue 的插槽(Slot)
1. 默认插槽
<!-- 父组件 -->
<child-component>
<p>父组件内容</p>
</child-component>
<!-- 子组件 -->
<template><slot></slot></template>
2. 具名插槽
- 父组件通过
v-slot:name
指定插入位置。
<!-- 父组件 -->
<child-component>
<template v-slot:header><h1>头部</h1></template>
</child-component>
<!-- 子组件 -->
<template><slot name="header"></slot></template>
3. 作用域插槽
<!-- 子组件 -->
<slot :message="childMsg">默认内容</slot>
<!-- 父组件 -->
<template v-slot:default="slotProps">
{{ slotProps.message }}
</template>
十七、Vue 响应式追踪机制
- 依赖收集:组件渲染时读取数据,将组件与数据建立关联。
- 更新机制:数据变化时,触发关联组件重新渲染(基于
Proxy
的拦截操作)。
十八、Vue SSR(服务器端渲染)原理
- 通过服务器预渲染组件为 HTML,发送给客户端,提升 SEO 和首屏加载性能。
- 核心 API:
createApp
:创建 Vue 应用实例。
renderToString
:将应用渲染为 HTML 字符串。
十九、Pinia 数据存储方式
- 默认存储:状态存储在内存中,页面刷新会丢失。
- 持久化存储:通过插件
pinia-plugin-persistedstate
存入 localStorage
/sessionStorage
。
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); // 启用持久化插件
二十、Vue Router 模式对比
模式 | 原理 | URL 示例 | 特点 |
---|
hash | 通过 URL 哈希值(# )路由 | https://a.com/#/home | 兼容性好,URL 含 # ,无需服务端配置 |
history | 使用 HTML5 History API | https://a.com/home | URL 简洁,需服务端配置回退到 index.html |
abstract | 适用于非浏览器环境(如 Node) | 无实际 URL 对应 | 用于 SSR 等场景 |
二十一、状态管理库适用场景
- 多组件共享状态(如用户登录状态、购物车数据)。
- 状态变化复杂,需集中管理和追踪。
- 跨页面/视图共享状态,避免组件间多层传递。
二十二、动态路由实现方式
- 路由参数:通过
:param
定义动态参数(如 /user/:id
),通过 $route.params.id
访问。
- 懒加载组件:动态导入组件,减少初始加载体积。
const User = () => import('./views/User.vue'); // 路由懒加载
- 导航守卫:通过
beforeEnter
钩子在路由进入前加载数据。
二十三、Vue 3 发布-订阅模式
- 基于
Proxy
实现响应式系统:数据变化时,Proxy
触发依赖收集的订阅者(组件/函数)重新渲染或执行回调。
二十四、keep-alive
缓存组件
- 作用:缓存不活动组件,避免重复渲染,提升性能。
- 用法:
<keep-alive include="ComponentA"> <!-- 缓存指定组件 -->
<router-view></router-view>
</keep-alive>
- 属性:
include
:指定缓存的组件名称或正则。
exclude
:指定不缓存的组件名称或正则。
二十五、Vue 懒加载实现方式
- 路由级懒加载:动态导入组件(
() => import('路径')
)。
- 组件级懒加载:使用
defineAsyncComponent
定义异步组件。
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() => import('./Async.vue'));
二十六、Vue 打包配置要点
- 代码分割:利用动态导入(
import()
)实现按需加载。
- 资源优化:压缩图片、字体,移除未使用代码(Tree Shaking)。
- 环境变量:通过
process.env.NODE_ENV
区分开发/生产环境,配置不同打包策略。
- 性能优化:开启 Gzip 压缩,使用 CDN 引入第三方库。
二十七、Vue 的核心优点
- 易学易用:语法简洁,文档友好,入门门槛低。
- 高性能响应式:基于
Proxy
的响应式系统,高效追踪数据变化。
- 组件化开发:便于复用和维护,适合构建大型应用。
- 灵活性强:支持选项式与组合式 API,适应不同项目规模。
二十八、nextTick
的作用
- 场景:在数据更新后,需操作最新 DOM 时使用(如获取更新后的元素尺寸)。
- 原理:等待 Vue 异步更新队列执行完毕,确保 DOM 已渲染完成。
this.count = 10; // 修改数据
this.$nextTick(() => {
console.log(this.$refs.div.clientWidth); // 获取更新后的 DOM 尺寸
});