Object.defineProperty(Vue 2.x)。initData),通过new Observer对data中的属性进行处理;walk方法遍历属性,通过defineReactive函数重定义属性;getter和setter:
watcher存入dep);watcher更新视图(dep.notify())。Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.depend(); // 收集依赖
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
dep.notify(); // 通知更新
}
});
data中的数组,重写其原型链,指向自定义的arrayMethods(基于Array.prototype创建);push、pop、shift、unshift、splice、sort、reverse;push、unshift、splice添加的元素)通过observeArray进行深度监控;dep.notify(),通知视图更新。watcher放入队列(queueWatcher),并过滤重复watcher;nextTick异步执行队列中的watcher(flushSchedulerQueue),实现批量更新。Promise.then(浏览器支持时)、MutationObserver;setImmediate(IE 支持)、setTimeout(fn, 0)。nextTick时,回调函数存入callbacks队列;flushCallbacks,依次执行队列中的回调。computed属性对应一个特殊watcher(computedWatcher),默认lazy: true;watcher.evaluate()计算结果,并标记dirty: false;dirty: true,下次取值重新计算。deep: true时,watch会通过traverse函数递归遍历对象 / 数组的所有属性;getter,将当前watcher存入其依赖(dep);watcher执行更新。| 生命周期钩子 | 触发时机 | 常见用途 |
|---|---|---|
beforeCreate |
实例初始化后,数据观测前 | 无(无法访问data、methods) |
created |
实例创建完成,数据观测完成 | 数据请求、初始化操作(无 DOM) |
beforeMount |
挂载开始前,render首次调用 |
预处理数据 |
mounted |
实例挂载完成,vm.$el替换 DOM |
DOM 操作(如初始化插件) |
beforeUpdate |
数据更新后,虚拟 DOM 渲染前 | 进一步修改数据(不触发额外渲染) |
updated |
虚拟 DOM 渲染与打补丁后 | 依赖 DOM 的操作(避免在此修改数据) |
beforeDestroy |
实例销毁前 | 清理定时器、解绑事件($off) |
destroyed |
实例销毁后 | 最终资源释放 |
mounted,此时 DOM 已渲染,可配合 DOM 操作处理请求结果。created,因mounted在 SSR 中不执行。created中 DOM 未就绪,不适合 DOM 操作。setInterval);window.scroll、document.mousemove);template → AST(抽象语法树) → 优化 AST → 生成render函数。
render函数(如_c('div', {attrs: {id: 'app'}}, [_v('text')]))。| 维度 | v-if |
v-show |
|---|---|---|
| 渲染逻辑 | 条件不成立时,不生成 DOM 节点 | 始终生成 DOM,通过display样式控制显示 / 隐藏 |
| 性能消耗 | 切换时销毁 / 重建节点(初始渲染成本低,切换成本高) | 仅切换样式(初始渲染成本高,切换成本低) |
| 适用场景 | 条件少变(如权限判断) | 条件频繁切换(如 tab 切换) |
v-for优先级高于v-if,连用会导致每次循环都执行v-if判断,即使部分元素无需渲染,仍会遍历整个列表,造成性能浪费。_l(列表, (item) => (条件 ? 渲染 : 不渲染)),循环不会因v-if提前终止。function vnode(tag, data, key, children, text) {
return {
tag: 'div', // 标签名(如'div'、'span')
data: { id: 'app' }, // 属性(如id、class、事件)
key: 'unique-key', // 唯一标识(优化diff)
children: [/* 子vnode */], // 子节点
text: 'hello' // 文本内容(若为文本节点)
};
}
oldCh与newCh);addVnodes);removeVnodes);oldStartIdx、oldEndIdx、newStartIdx、newEndIdx);sameVnode判断是否可复用),命中则移动指针并更新;key查找可复用节点,移动或新增节点;