1. Vue 有了数据响应式,为何还要 diff ?
答: 响应式只能告诉 "哪个组件需要更新",但不告诉 "DOM如何最小化变更"。diff(虚拟 DOM 对比)用来在旧/新 VNode之间定位差异,生成最小 DOM。
操作序列 (如移动/插入/删除子节点),尤其列表更新、节点重排时至关重要(如基于 key
的最长递增子序列优化)。
2. Vue 3 为什么不做(或基本不需要)时间分片(time slicing)?
答:
React 引入时间分片为可中断渲染 ,解决大渲染任务阻塞事件响应。
Vue 3 采用编译期优化(Patch Flags、静态提升)+ 非常细粒度的更新(effect/scheduler) ,单次更新开销更小,通常同步渲染即可完成 。
Vue也有调度器(微任务队列)做批量与去重 ,在多数场景无需引入复杂的可中断机制;若极端场景需要让步,可自行 requestIdleCallback
分块渲染。
3. Vue 3 为什么引入 Composition API?
答: 解决 Options API 的逻辑切散 与复用笨重 问题。CompositionAPI 用函数(setup
/hooks)按特性聚合逻辑,易抽离为可复用的composable;同时更友好地支持 TS 类型推断、逻辑组织与代码分割。
4. 说一下 Vue 事件机制,并手写 $on/$off/$emit/$once
js
class Emitter {
constructor(){ this.events = new Map(); }
$on(type, handler){
(this.events.get(type) || this.events.set(type, new Set()).get(type)).add(handler);
}
$off(type, handler){
if (!type) { this.events.clear(); return; }
const set = this.events.get(type);
if (!set) return;
if (!handler) set.clear();
else set.delete(handler);
}
$emit(type, ...args){
const set = this.events.get(type);
if (!set) return;
[...set].forEach(fn => fn(...args));
}
$once(type, handler){
const wrap = (...args)=>{ handler(...args); this.$off(type, wrap); };
this.$on(type, wrap);
}
}
答: Vue 内部事件中心机制类似,$emit
触发事件,$on
注册监听,$off
移除,$once
注册一次性监听。
5) computed
为什么可以依赖另一个 computed
?
答: computed
内部是惰性副作用(lazy effect) ,访问它会执行
getter 并 track 依赖。A 计算属性读取 B 时,会触发 B 的 getter → 建立
A 对 B 的依赖链。B 的依赖变化导致 B 的 dirty
,进而在下次读取 A
时联动更新。
6) 说一下 vm.$set
原理(Vue 2)
答: Vue 2 用 Object.defineProperty
劫持,新增属性默认不响应 。$set(obj, key, val)
会:
1)若是数组:调用 splice
触发依赖通知;
- 若是对象:执行
defineReactive(obj, key, val)
把新键转为响应式,并dep.notify()
通知视图。
Vue 3 用 Proxy
,无需 $set
。
7) 怎么在 Vue 中定义全局方法?
答:
- Vue 2:
Vue.prototype.$xxx = fn
; - Vue 3:
app.config.globalProperties.$xxx = fn;
更推荐用插件或 provide/inject 实现解耦。
8) Vue 中父组件怎么监听到子组件的生命周期?
答: Vue 2 可用 @hook:mounted
,Vue 3 需子组件 emit
自定义事件,父组件监听。或子用 expose()
,父用 ref
。
9) Vue 组件里写的原生 addEventListener
要销毁吗?
答: 绑定到 window
/document
/全局对象的必须在 beforeUnmount
清理。模板指令绑定 Vue 会自动清理。推荐 AbortController
简化。
10) 说说 Vue 3 的响应式设计原理
答: 基于 Proxy:
track
:读时收集依赖;trigger
:写时通知effect;ref
包装.value
;computed
用 dirty 缓存;- 迭代 key / 数组 方法额外处理。
11) Vue 列表 diff 为何强调 key
?
答: key
保证节点稳定身份,减少错误复用与无谓重建。缺失时可能导致状态错乱。
12) Vue 3 的编译期优化有哪些?
答: 静态提升、Patch Flags、VNode/事件缓存等,最大化缩减运行时 diff。
13) watch
、watchEffect
、computed
区别?
答:
computed
:有返回值、带缓存;watch
:精确侦听源,能拿到新旧值;watchEffect
:立即执行,自动依赖收集。
14) provide/inject
与全局单例的取舍
答: provide/inject 是组件树范围的依赖注入,作用域隔离强,可测试。全局单例更耦合。
15) Vue 2 与 Vue 3 的 v-model
差异
答: Vue 2 默认 value
/input
,Vue 3 改为 modelValue
/update:modelValue
,且支持多绑定。
16) 组件缓存:keep-alive
原理
答: 缓存组件实例,不销毁。生命周期有 activated/deactivated
。配合 include / exclude 控制。
17) Vue 项目的性能优化
答:
- 合理 key;
- computed 代替模板大计算;
- 路由懒加载;
- 图片懒加载;
- 打包 Tree-shaking。
18) Vue 与事件循环
答: Vue 更新任务进入微任务队列,nextTick 用 Promise/MO/降级。这样实现批量与去重。
19) SPA 的安全防护
答:
- XSS:避免 v-html、CSP、防止注入;
- CSRF:SameSite、Token。
20) SSR/CSR/SSG 区别
答: CSR 部署简单;SSR 首屏快/SEO好但复杂;SSG 静态内容高效。