1. Vue3 响应式原理中,Proxy 和 Reflect 是如何配合使用的?为何要结合 Reflect?
- Proxy 用于拦截对象操作(如
get
、set
、deleteProperty
),Reflect 提供默认行为的方法(如Reflect.get
)。 - 配合方式 :在 Proxy 的
get
/set
等陷阱中,通过Reflect
执行原始操作,确保代理对象行为与原始对象一致。
javascript
const proxy = new Proxy(target, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver); // 保持 this 正确指向
},
set(target, key, value, receiver) {
trigger(target, key); // 触发更新
return Reflect.set(target, key, value, receiver);
}
});
-
为何用 Reflect:
- 避免直接操作目标对象导致
this
指向错误(例如访问对象方法时,this
应指向代理对象而非原对象)。 - 兼容性更好,Reflect 方法返回布尔值(如
Reflect.set
返回是否设置成功),方便错误处理。
- 避免直接操作目标对象导致
2. Vue3 的"静态节点提升"和"PatchFlag"如何优化 diff 算法?
-
静态节点提升(Static Node Hoisting) :
- 编译阶段将静态节点(无动态绑定的元素)提取到渲染函数外,生成一次后复用,避免 diff 时重复比较。
-
PatchFlag:
- 在编译时为动态节点添加标记(如
1
表示文本动态,8
表示 props 动态),diff 时仅对比带标记的部分。
- 在编译时为动态节点添加标记(如
-
协同优化:
- 静态节点直接跳过 diff,动态节点通过 PatchFlag 缩小对比范围,整体复杂度从 O(n) 降低到接近 O(1) 的动态部分。
3. 如何实现 Vue 自定义渲染器(如渲染到 Canvas)?
步骤:
- 使用
createRenderer
创建渲染器,提供自定义的createElement
、patchProp
、insert
等方法:
typescript
const { createRenderer } = Vue;
const renderer = createRenderer({
createElement(type) { /* 创建 Canvas 元素 */ },
patchProp(el, key, prev, next) { /* 更新属性 */ },
insert(el, parent) { /* 插入到 Canvas 层级 */ }
});
在组件中使用 renderer.createApp
替代默认的 createApp
:
ini
const app = renderer.createApp(RootComponent);
app.mount('#canvas-container');
-
实现 Canvas 渲染逻辑:
- 用
requestAnimationFrame
批量更新,避免频繁重绘。 - 将虚拟节点映射为 Canvas 的绘制指令(如
drawRect
、drawText
)。
- 用
4. Composition API 中如何避免"响应式数据滥用"?
-
合理选择 API:
reactive
:深响应式对象,适合复杂数据结构(如嵌套对象)。ref
:包装基本类型,通过.value
访问,适用于独立值。shallowRef
/shallowReactive
:浅层响应式,避免深层递归带来的性能损耗。
-
优化场景:
- 大数组或只读数据:使用
shallowRef
或markRaw
跳过代理。 - 频繁更新的数据:使用
ref
替代reactive
,减少 Proxy 层级。
- 大数组或只读数据:使用
5. 高性能长列表滚动加载如何结合 Vue 和 Intersection Observer?
关键思路:
- 虚拟列表 :仅渲染可见区域的 DOM 元素,通过
transform
偏移模拟滚动。 - Intersection Observer 监听元素是否进入视口,动态加载数据:
scss
const observer = new IntersectionObserver((entries) => {
if (entries.isIntersecting) {
loadMore(); // 加载下一页数据
}
});
observer.observe(loaderRef.value); // 监听"加载更多"元素
-
响应式优化:
- 使用
shallowRef
存储列表数据,避免深响应式开销。 - 用
v-memo
(Vue3.2+)缓存已渲染的列表项,避免重复渲染。
- 使用
5. Vue3 中 v-model 的自定义实现及 .sync 替代方案
-
v-model 原理:
- 默认绑定
modelValue
prop 和update:modelValue
事件。
- 默认绑定
xml
<!-- 自定义组件 -->
<Child :modelValue="value" @update:modelValue="value = $event" />
等价语法:
vbnet
// 组件内部
props: ['modelValue'],
emits: ['update:modelValue']
替代 .sync:
- Vue3 移除了
.sync
,改用v-model:propName
:
xml
<Child :title="pageTitle" @update:title="pageTitle = $event" />
<!-- 简写为 -->
<Child v-model:title="pageTitle" />