Vue 2.5 源码大体概述

前些时间大概看了一下Vue的官方文档,也大概了解过 Vue 实现数据绑定的原理,但是还是想再深入得了解其具体的代码细节,便抽了些时间来阅读源码。看了个大概,另外自己水平有限,也只能把自己看懂的分享给大家。

Vue 的源码用了flow进行类型检测等工作,真正生产环境的代码是 flow编译而成的,所以在IDE中阅读代码时会出现很多代码错误的提示,如果只需要阅读而不对源码进行修改和单元测试,则不必过多考虑。需要的话可以去阅读一下flow这个工具的用法, 这里是官网: https://flow.org/

另外,源码中的语法大都是 ES6 的标准,还运用了很多Object.defineProperty来配置对象成员的 get 和 set 钩子。

构造过程 new Vue({...})

Vue的构造器在 src/core/instance/index.js 中,但是在加载Vue这个API的时会先对它进行初始化,代码位置在 src/core/index.js 中

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

Vue.version = '__VERSION__'

export default Vue

可以看到这里在 Vue 构造器 被导出之前运行了 initGlobalAPI() 来扩展Vue 构造器本身的属性及方法(javascript 作为一个基于原型的 OO 语言, 其中一个函数也是一个对象,因此是可以有自己的方法和属性的)。

initGlobalAPI() 在 src/core/global-api/index.js 中

再看 Vue 构造器

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

在构造器被运行之前,依然运行了一些函数来初始化Vue 原型的方法,这里很重要,但是在第一篇文章里就不详述了。

在构造 vue 对象时,运行了 _init(options) 函数来初始化,在src/core/instance/init.js 中

function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++
    ......
    // merge options
    // 在之前对构造器本身及其原型进行了扩展,这里进行合并处理
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    ......
    vm._self = vm
    initLifecycle(vm) // 初始化生命周期
    initEvents(vm) // 初始化事件及时间处理
    initRender(vm) // 初始化render
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm) // 初始化 data, 的监视等
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    ......
    if (vm.$options.el) {
      vm.$mount(vm.$options.el) // 挂载
    }
  }
}

在挂载之前先要对生命周期,模板渲染等进行初始化,比较重要的是建立对数据的监视来实现动态绑定以在数据更改时重新渲染VDOM 并更新DOM。

挂载时要进行模板的编译和DOM的生成,这一步之后,就顺利构造完成了。

VDOM

Vue 同 react 一样, 运用了自己的虚拟DOM来实现DOM的更新,大体可以理解为在数据发生变化时先建立一个虚拟的DOM,并且与之前的虚拟DOM进行比较,最后经过diff 之后找到不同并通过 patch 来更行真正的DOM。其优点在于避免了大量的DOM操作(因为DOM操作很费资源)。

这里不进行详细分析,但是推荐给大家一篇文章,里面介绍了诸多框架中数据监测的实现
http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html

模板编译

Vue 的模板编译大体需要经过一下几个步骤

  1. 由template编译成 ast render 函数(AST是指抽象语法树,具体就不说了,因为我也不会)
  2. 运行render 函数,编译成 vnode(虚拟DOM节点)
  3. 通过patch更行DOM

而具体的模板编译和patch都是相对比较复杂的算法,这里就先不细说(以后可能也细说不了,得看我个人造化了)

数据监视(数据绑定)

Vue 的数据绑定主要是通过get 和 set 钩子来实现的,而钩子函数究竟干了什么呢,其实在初始化的过程中建立了一系列的 Observer 对象来监视数据的变化,在 Observer 中又有 Watcher 对象,负责监视到数据变化之后的操作(不知道说的对不对,个人理解吧)。Observer 的建立过程中就设置了诸多get set 钩子。Watcher则是在挂载时建立(也有可能在其他地方也建立了但是还没有读到)。

结语

以上就是对Vue 2.5 源码的概述,由于个人水平有限,可能有很多错误,希望大家能提出,共同学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342