【Vue】基础(虚拟DOM & 响应式原理)
程序员文章站
2022-03-25 16:59:50
Vue虚拟DOM是实现响应式的核心,弄清楚虚拟DOM和Vue响应式原理,对写代码有参考作用 ......
虚拟 dom
vue 通过建立一个虚拟 dom 来追踪自己要如何改变真实 dom
在vue中定义虚拟节点(vnode)描述节点信息
export default class vnode { tag: string | void; data: vnodedata | void; children: ?array<vnode>; text: string | void; elm: node | void; ns: string | void; context: component | void; // rendered in this component's scope key: string | number | void; componentoptions: vnodecomponentoptions | void; componentinstance: component | void; // component instance parent: vnode | void; // component placeholder node
这里描述节点文本,标签信息(tag),真实dom节点(elm),节点的data信息,子节点,父节点等信息
“虚拟 dom”是我们对由 vue 组件树建立起来的整个 vnode 树的称呼
从结构可以看到根节点(parent为空)就可以表示整个树
有了虚拟 dom ,vue就会比较差异,更新真实dom
比较差异是在patch.js里面的patch方法(补丁)
响应式原理
vue的响应式大概会经过下面几个阶段
1. 使用 object.defineproperty 把属性全部转为getter/setter
2. 属性变更时通知观察者(watcher)变更
3. watcher触发重新渲染生成虚拟 dom
4. vue框架遍历计算新旧虚拟 dom差异
4.1 由于 javascript 的限制,vue 不能检测数组和对象的变化
5. 加载操作,将差异局部修改到真实 dom
从源码解读vue响应式(部分代码有截取)
//截取部分代码 object.defineproperty(obj, key, { get: function reactivegetter () { const value = getter ? getter.call(obj) : val return value }, set: function reactivesetter (newval) { const value = getter ? getter.call(obj) : val /* eslint-disable no-self-compare */ if (newval === value || (newval !== newval && value !== value)) { return } /* eslint-enable no-self-compare */ if (process.env.node_env !== 'production' && customsetter) { customsetter() } // #7981: for accessor properties without setter if (getter && !setter) return if (setter) { setter.call(obj, newval) } else { val = newval } childob = !shallow && observe(newval) dep.notify() } })
setter前面的都是赋值的判断,
1. 值是否相等,
2. 是否自定义setter函数,
3. 是否只读
4. 最后一句dep.notify(),dep是什么类型,这里看都猜到是通知,具体定义
const dep = new dep()
export default class dep { static target: ?watcher; id: number; subs: array<watcher>; constructor () { this.id = uid++ this.subs = [] } addsub (sub: watcher) { this.subs.push(sub) } removesub (sub: watcher) { remove(this.subs, sub) } depend () { if (dep.target) { dep.target.adddep(this) } } notify () { // stabilize the subscriber list first const subs = this.subs.slice() if (process.env.node_env !== 'production' && !config.async) { // subs aren't sorted in scheduler if not running async // we need to sort them now to make sure they fire in correct // order subs.sort((a, b) => a.id - b.id) } for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } }
可以看到,dep类 提供一个订阅,通知的功能
最后我们看一下订阅的目标watcher是做什么
watcher最重要的一个方法update
update () { /* istanbul ignore else */ if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queuewatcher(this) } }
转发请标明出处:https://www.cnblogs.com/wilsonpan/p/12744695.html