Vuejs 核心代码解析之初始化

发布于 2021-11-05 12:47:34 字数 4975 浏览 984 评论 0

首先看最简单的一个 two way:

//初始化过程
var vm = new Vue({
  data:{
    'show':'init'
  }
});

//编译过程
vm.$mount('#node');

上面是一个最简单的双向绑定,今天要说的就是 初始化的过程,这个过程相对比较简单,主要有以下:

  • 初始化
  • 为 vm 添加 data 访问器
  • 创建 Observer, 并未 data 定义 __ob__ 属性
  • 创建 __ob__ 访问器,与编译触发相关联

以下代码解释:

exports._init = function (options) {
  options = options || {}

  this.$el           = null
  this.$root         = options._root || this

  this._watcherList  = [] // all watchers as an array
  this._watchers     = {} // internal watchers as a hash
  this._directives   = [] // all directives

  // 标记,避免被观察
  this._isRebirth = true

  // events bookkeeping
  this._events         = {}    // registered callbacks
  this._eventsCount    = {}    // for $broadcast optimization
  this._eventCancelled = false // for event cancellation

  // block instance properties
  this._isBlock     = false
  this._blockStart  =          // @type {CommentNode}
  this._blockEnd    = null     // @type {CommentNode}

  // lifecycle state
  this._isCompiled  =
  this._isDestroyed =
  this._isReady     =
  this._isAttached  =
  this._isBeingDestroyed = false
  this._unlinkFn    = null

  // children
  this._children = []
  this._childCtors = {}

  // transcluded components that belong to the parent.
  // need to keep track of them so that we can call
  // attached/detached hooks on them.
  this._transCpnts = []


  // props used in v-repeat diffing
  this._new = true
  this._reused = false

  // merge options.
  options = this.$options = mergeOptions(
    this.constructor.options,
    options,
    this
  )

  // set data after merge.
  this._data = options.data || {}

  // initialize data observation and scope inheritance.
  this._initScope()
}

与双向绑定关键为最后2个:

// set data after merge.
this._data = options.data || {}

// initialize data observation and scope inheritance.
this._initScope()

执行 _initScope 初始化访问器

//initScope
exports._initScope = function () {
  //add accessor
  this._initData()
}

/**
 * Initialize the data.
 */

exports._initData = function () {
  // proxy data on instance
  var data = this._data
  var i, key
  var keys = Object.keys(data)
  i = keys.length
  while (i--) {
    key = keys[i]
    if (!_.isReserved(key)) {
      //vm.prop 与 vm._data.prop 代理
      this._proxy(key)
    }
  }
  // observe data
  Observer.create(data).addVm(this)
}

initData 主要分为两部分:

  • vm.prop 与 vm._data.prop 之间创建访问器
  • 创建 Observer,以及推入 vms
//vm.prop 与 vm._data.prop  之间创建访问器

exports._proxy = function (key) {
  // need to store ref to self here
  // because these getter/setters might
  // be called by child instances!
  var self = this
  Object.defineProperty(self, key, {
    configurable: true,
    enumerable: true,
    get: function proxyGetter () {
      return self._data[key]
    },
    set: function proxySetter (val) {
      self._data[key] = val
    }
  })
}

Observer

function Observer (value, type) {
  this.id = ++uid
  this.value = value
  this.active = true
  this.deps = []
  _.define(value, '__ob__', this)
  if (type === OBJECT) {
    this.walk(value)
  }
}

//跳过$和_
p.walk = function (obj) {
  var keys = Object.keys(obj)
  var i = keys.length
  var key, prefix
  while (i--) {
    key = keys[i]
    prefix = key.charCodeAt(0)
    if (prefix !== 0x24 && prefix !== 0x5F) { // skip $ or _
      this.convert(key, obj[key])
    }
  }
}

//最重要的一步,当然这部要配合 vm.$mount来看
p.convert = function (key, val) {
  var ob = this
  var childOb = ob.observe(val)
  var dep = new Dep()
  if (childOb) {
    childOb.deps.push(dep)
  }
  Object.defineProperty(ob.value, key, {
    enumerable: true,
    configurable: true,
    get: function () {
      // Observer.target is a watcher whose getter is
      // currently being evaluated.
      if (ob.active && Observer.target) {
        Observer.target.addDep(dep)
      }
      return val
    },
    set: function (newVal) {
      if (newVal === val) return
      // remove dep from old value
      var oldChildOb = val && val.__ob__
      if (oldChildOb) {
        oldChildOb.deps.$remove(dep)
      }
      val = newVal
      // add dep to new value
      var newChildOb = ob.observe(newVal)
      if (newChildOb) {
        newChildOb.deps.push(dep)
      }
      dep.notify()
    }
  })
}

vue 的初始化还算简单,compile 阶段还正在学习中。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

躲猫猫

暂无简介

0 文章
0 评论
570 人气
更多

推荐作者

qq_Yqvrrd

文章 0 评论 0

2503248646

文章 0 评论 0

浮生未歇

文章 0 评论 0

养猫人

文章 0 评论 0

第七度阳光i

文章 0 评论 0

新雨望断虹

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文