深入Vue.js从源码开始(二)

49次阅读

共计 2704 个字符,预计需要花费 7 分钟才能阅读完成。

从入口开始
我们之前提到过 Vue.js 构建过程,在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/entry-runtime-with-compiler.js:
摘选 entry-runtime-with-compiler.js
import config from ‘core/config’
import {warn, cached} from ‘core/util/index’
import {mark, measure} from ‘core/util/perf’

// 主角在这里
import Vue from ‘./runtime/index’
import {query} from ‘./util/index’
import {compileToFunctions} from ‘./compiler/index’
import {shouldDecodeNewlines, shouldDecodeNewlinesForHref} from ‘./util/compat’

Vue 的入口
在这个入口 JS 的上方我们可以找到 Vue 的来源:import Vue from ‘./runtime/index’,我们先来看一下这块儿的实现,它定义在 src/platforms/web/runtime/index.js 中:
import Vue from ‘core/index’
import config from ‘core/config’
import {extend, noop} from ‘shared/util’

这里关键的代码是 import Vue from ‘core/index’ 是真正初始化 Vue 的地方 [/src/core/index.js]
import Vue from ‘./instance/index’
import {initGlobalAPI} from ‘./global-api/index’

这里有 2 处关键的代码,import Vue from ‘./instance/index'(./ 指的是当前目录) 和 initGlobalAPI(Vue),初始化全局 Vue API,我们先来看第一部分,在 src/core/instance/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

1
在这里,我们终于看到了 Vue 的庐山真面目,它实际上就是一个用 Function 实现的类,我们只能通过 new Vue 去实例化它
为何 Vue 不用 ES6 的 Class 去实现呢?我们往后看这里有很多 xxxMixin 的函数调用,并把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法(这里具体的细节会在之后的文章介绍,这里不展开),Vue 按功能把这些扩展分散到多个模块中去实现,而不是在一个模块里实现所有,这种方式是用 Class 难以实现的。这么做的好处是非常方便代码的维护和管理,这种编程技巧也非常值得我们去学习。
initGlobalAPI
Vue.js 在整个初始化过程中,除了给它的原型 prototype 上扩展方法,还会给 Vue 这个对象本身扩展全局的静态方法,它的定义在 src/core/global-api/index.js 中:
export function initGlobalAPI (Vue: GlobalAPI) {
// config
const configDef = {}
configDef.get = () => config
if (process.env.NODE_ENV !== ‘production’) {
configDef.set = () => {
warn(
‘Do not replace the Vue.config object, set individual fields instead.’
)
}
}
Object.defineProperty(Vue, ‘config’, configDef)

// exposed util methods.
// NOTE: these are not considered part of the public API – avoid relying on
// them unless you are aware of the risk.
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}

Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick

Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + ‘s’] = Object.create(null)
})

// this is used to identify the “base” constructor to extend all plain-object
// components with in Weex’s multi-instance scenarios.
Vue.options._base = Vue

extend(Vue.options.components, builtInComponents)

initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
}

这里就是在 Vue 上扩展的一些全局方法的定义,Vue 官网中关于全局 API 都可以在这里找到,这里不会介绍细节,会在之后的章节我们具体介绍到某个 API 的时候会详细介绍。有一点要注意的是,Vue.util 暴露的方法最好不要依赖,因为它可能经常会发生变化,是不稳定的。

正文完
 0