美文网首页Web前端之路
关于一些Vue的文章。(7)

关于一些Vue的文章。(7)

作者: 三毛丶 | 来源:发表于2017-04-23 08:31 被阅读27次

    原文链接我的blog,欢迎STAR。

    首先安利一波福利,有没有用vscode的小伙伴?推荐一个神奇的字体,自从用了这个字体,敲代码效率简直上天了。先上图看看效果:

    全等全等 箭头函数箭头函数 小于等于小于等于

    还有其他许多,就不一一列举出来了。
    有没有看上了的?
    没有我等下再来问。

    这次推荐的一篇文章来自,阅读文章有利于加深对Vue程序结构的了解,虽然是 1.0版本,不过好在 2.0 版本保留了绝大部分 1.0 的API。

    在这篇文章里我将是这几个月来对 Vue 学习的一个小结。


    思路

    Vue 和其他的 MVVM 思路是类似的:

    主要是为了实现三个过程:

    1. Observer: 通过Observer对data进行监听,并且提供订阅某个数据项的变化的能力。利用Object.defineProperty, 将data里的每个属性全部转化为getter/setter,已遍拦截对象赋值与取值操作;

    2. Compiler: 将template 解析为 render()方法;

    3. watcher: Compiler 的解析结果与 Observer 结合起来,在 Observer 监听到数据发生改变时,接受通知,进而触发 re-render, 重新渲染DOM。


    new Vue

    我们从 new Vue 开始,

    上图即是官网给出的一张生命周期图,主要是四个过程:

    • create: 在 new Vue() 时会运行,创建出 Vue 对象。
    • mount: 会根据 el, template, render 等,生成 Vnode, 完成 diff 算法后挂载到 DOM 上。
    • updata: 当数据发生改变时,会重新渲染 DOM。
    • destory: Vue 销毁时会运行。

    现在,我们进入源码,分析具体的实现:

    • Create: 首先运行new vue()的时候,会进入_init
      其中关键部分的代码如下:

    可以看出在 beforeCreatecreated 只有initState, initState 是用于实现data observerevent/watcher

    • Mount: 在_init最后,会运行 vm.$mount 方法:

    具体 vm.$mount 的分析,请看上篇。最后进行了 render(), 从而会有Vnode, 经过 DIFF 算法后会有真实 DOM ;

    • Update: DOM 之后,会进行update方法:

      vm._watcher = new Watcher(vm, () => {
        vm._update(vm._render(), hydrating)
      }, noop)
      

    将以上用一张序列图表示也就是:


    深入响应式原理 (Observer, watcher)

    MVVM 框架有一个很重要的特征:就是当数据放生变化后,会自动更新对应的DOM节点。 Vue 是怎么实现的?

    以上是来自官网的一张图。

    前面提到在 beforeCreatecreated 两个生命周期钩子函数之间会运行 initState() 方法。

    initState() 源码里:

    在这个方法里,会对props, data, computed 等属性利用 Object.defineProperty 将这些属性全部转化为 getter/setter

    我们以 initData() 为例子进行分析:

    这里有一个值得注意的地方, proxy(vm, "_data", keys[i]), 设置 vm._data为代理,具体作用是实现 vm.a === vm._data.a

    initData()最后 会进行 observe(data, this)

    observe()里,既是转化为 getter/setter

      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
          const value = getter ? getter.call(obj) : val
          // 只有在有Dep.target时才说明是Vue内部依赖收集过程触发的getter
          // 那么这个时候就需要执行dep.depend(),将watcher(Dep.target的实际值)添加到dep的subs数组中
          // 对于其他时候,比如dom事件回调函数中访问这个变量导致触发的getter并不需要执行依赖收集,直接返回value即可
          if (Dep.target) {
            dep.depend()
            if (childOb) {
              // 如果value在observe过程中生成了ob实例,那么就让ob的dep也收集依赖
              childOb.dep.depend()
            }
            if (isArray(value)) {
                //如果数组元素也是对象,那么他们observe过程也生成了ob实例
                dependArray(value)
            }
          }
          return value
        },
        set: function reactiveSetter (newVal) {
          var value = getter ? getter.call(obj) : val
          if (newVal === value) {
            return
          }
          if (setter) {
            setter.call(obj, newVal)
          } else {
            val = newVal
          }
          // observe 这个新数据
          childOb = observe(newVal)
          // 通知到dep 进行数据更新。
          dep.notify()
        }
      })
      
    

    到这个时候,Observer 监听已经完成,如果数据更新,我们会进行 dep.notify() 方法:

    dep.notify() , 方法里会执行update()

    update() , 中会进行
    queueWatcher() 方法:

    queueWatcher(), 目的是通过 nextTicker 来执行 run()

    run() 里,其实就是执行 this.get() 方法:

    get() 方法里,会运行 this.getter(), 方法来更新 DOM 。

    this.getter()方法是啥?

    再就是上文中所提到的new Watcher(), 的第二个参数。

    vm._watcher = new Watcher(vm, () => {
      vm._update(vm._render(), hydrating)
    }, noop)
    
    

    而在 new Watcher 构造完成后,会调用 this.get() ,触发 this.getter(),方法触发 DOM 更新。

    具体可以看watcher.js:

    截一个关键代码部分的图:

    以上,用一张序列图来表示,既就是:

    对以上总结:

    • 首先 _init ,对属性利用 Object.defineProperty,将属性转为 getter/setter,在 setter 方法里,会调用 dep.notify()
    • vm 设置 new Watcher
    • data 变化时,进行数据跟新。

    完。

    相关文章

      网友评论

        本文标题:关于一些Vue的文章。(7)

        本文链接:https://www.haomeiwen.com/subject/hubezttx.html