1. Vue 是什么框架?
回答:
Vue 是一套用于构建用户界面的渐进式 JavaScript 框架。它有几个显著特点:
- 渐进式:可以逐步采用,从简单的视图层开始,逐步扩展到完整的单页应用
- 组件化:通过组件系统构建可复用的 UI 组件
- 响应式:数据驱动视图,自动追踪依赖并更新 DOM
- 虚拟 DOM:高效地更新和渲染组件
Vue 既适合小型项目快速开发,也能胜任复杂的大型应用,生态丰富,学习曲线平缓。
2、解释一下MVVM
MVVM(Model-View-ViewModel)是一种将用户界面逻辑与业务逻辑分离的架构模式,Vue是其典型实现。在Vue中:
- Model对应组件中的
data,管理原始数据; - View是模板,负责UI呈现;
- ViewModel由Vue实例实现,通过响应式系统(Vue2用
Object.defineProperty/Vue3用Proxy)建立双向绑定,自动同步数据与视图。其核心优势在于:
- 自动更新:数据变动时通过虚拟DOM高效更新视图
- 指令系统(如
v-model)简化DOM操作 - 计算属性和侦听器处理衍生状态
- 组件化实现关注点分离
相比传统MVC,MVVM通过数据驱动视图,减少了手动DOM操作,提高了开发效率和可维护性。Vue的响应式系统会在组件渲染时收集依赖,数据变化时精准更新相关组件,这种机制使得Vue既能处理复杂应用状态,又能保持优秀的性能表现。
3. 组合式 API 和选项式 API 的区别及优缺点
回答:
选项式 API (Options API) :
- 通过
data,methods,computed等选项组织代码 - 优点:
-
- 结构清晰,适合初学者
- 相关功能分散在不同选项中但容易定位
- 更好的类型推断(TypeScript)
- 缺点:
-
- 逻辑关注点分散,大型组件难以维护
- 代码复用性较差
组合式 API (Composition API) :
- 使用
setup()函数和响应式 API 组织代码 - 优点:
-
- 逻辑关注点集中,更好组织复杂组件
- 更好的代码复用(自定义组合函数)
- 更灵活的类型系统
- 更好的 Tree-shaking 支持
- 缺点:
-
- 学习曲线稍陡峭
- 需要更多规范来保持代码整洁
适用场景:简单项目可用选项式,复杂项目推荐组合式。
4. 组合式 API 中的 setup 的作用及原理
回答:
setup 是组合式 API 的入口函数,它的作用包括:
- 定义响应式数据:使用
ref/reactive创建响应式状态 - 定义方法:直接在
setup中声明函数 - 返回模板使用的数据和方法:返回的对象会暴露给模板
- 生命周期钩子注册:使用
onMounted等函数注册生命周期
原理:
setup在组件实例创建之前执行,此时没有this上下文- 返回的对象会被代理到组件实例上,使模板可以访问
- 内部使用闭包保持响应式数据的引用
- 与模板的绑定是通过编译时的静态分析实现的
5. Vue3 为什么比 Vue2 打包体积更小?
回答:
Vue3 打包体积更小主要得益于以下优化:
- 更好的 Tree-shaking:模块化架构,按需引入功能
-
- Vue2 整个 API 都是可变的,难以 Tree-shaking
- Vue3 的 API 设计为可独立导入
- 编译器优化:
-
- 更高效的模板编译,生成更精简的运行时代码
- 静态节点提升(Hoist Static)减少运行时开销
- 代码重构:
-
- 移除了不常用的 API
- 重写了响应式系统,更精简高效
- 体积指标:
-
- Vue2 最小打包约 20KB
- Vue3 最小打包约 10KB(减少约 50%)
6. ref 和 reactive 的区别与使用场景
回答:
ref:
- 用于创建基础类型的响应式数据(也可用于对象)
- 通过
.value访问/修改值 - 原理:使用对象包装,通过 getter/setter 实现响应式
- 模板中自动解包,无需
.value
reactive:
- 用于创建对象类型的响应式数据
- 直接访问/修改属性
- 原理:使用 Proxy 实现深层响应式
- 不能解构,否则会失去响应性
使用场景:
- 基础类型用
ref - 复杂对象用
reactive - 组合函数返回推荐用
ref(保持一致性) - 需要解构时使用
toRefs处理reactive对象
7. Vue2 和 Vue3 生命周期对比
回答:
| Vue2 生命周期 | Vue3 生命周期 (选项式) | Vue3 组合式 API |
|---|---|---|
| beforeCreate | beforeCreate | 无直接对应 (在 setup 之前) |
| created | created | 无直接对应 (在 setup 之后) |
| beforeMount | beforeMount | onBeforeMount |
| mounted | mounted | onMounted |
| beforeUpdate | beforeUpdate | onBeforeUpdate |
| updated | updated | onUpdated |
| beforeDestroy | beforeUnmount | onBeforeUnmount |
| destroyed | unmounted | onUnmounted |
| errorCaptured | errorCaptured | onErrorCaptured |
| - | renderTracked | onRenderTracked |
| - | renderTriggered | onRenderTriggered |
主要变化:
destroyed更名为unmountedbeforeDestroy更名为beforeUnmount- 组合式 API 使用
onXxx函数注册生命周期 - 新增了调试相关的生命周期钩子
8. watch 和 watchEffect 的区别
回答:
watch:
- 需要明确指定监听的数据源和回调
- 惰性执行(默认不会立即执行)
- 提供旧值和新值
- 可以指定
deep和immediate选项 - 适合精确控制监听行为
watchEffect:
- 自动收集依赖,回调中使用的响应式数据都会被监听
- 立即执行一次(收集依赖)
- 不提供旧值
- 适合处理"副作用"逻辑
使用场景:
- 需要知道旧值/精确控制监听源时用
watch - 依赖多个状态且不需要旧值时用
watchEffect - 异步操作推荐使用
watch(可以清理副作用)
9. Vue 的 diff 算法原理
回答:
Vue 的 diff 算法是基于虚拟 DOM 的高效更新策略,核心是同级比较:
Vue2 的 diff 算法:
- 同级比较,不跨级
- 双端比较(头头、尾尾、头尾、尾头)
- 使用 key 识别可复用节点
- 就地复用策略(没有 key 时)
Vue3 的优化:
- 静态标记(PatchFlag):编译时标记动态节点
- 静态提升:提升静态节点到渲染函数外
- 事件缓存:缓存事件处理函数
- 更高效的 diff 策略:
-
- 预处理相同的前缀/后缀
- 最长递增子序列优化移动逻辑
关键点:
- key 的重要性:帮助识别节点身份
- 减少 DOM 操作是核心目标
- Vue3 的优化使 diff 效率提升约 30%
10. computed 和 watch 的区别
回答:
computed:
- 计算属性,基于依赖的响应式数据计算得出值
- 具有缓存性,依赖不变时不会重新计算
- 必须返回一个值
- 适合派生状态(如过滤列表、格式化数据)
watch:
- 监听数据变化执行回调
- 无返回值,用于执行"副作用"操作
- 可以访问旧值和新值
- 适合异步操作或复杂逻辑
使用场景:
- 需要基于现有数据计算新值时用
computed - 需要在数据变化时执行操作时用
watch - 计算开销大时特别适合用
computed(缓存优化)