当前位置: 移动技术网 > IT编程>网页制作>CSS > 【Vue】基础(虚拟DOM & 响应式原理)

【Vue】基础(虚拟DOM & 响应式原理)

2020年04月21日  | 移动技术网IT编程  | 我要评论

问道金头陀点化,鼠标指针,爱购宝

虚拟 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)
    }
  }

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网