您的浏览器不支持JavaScript或者JavaScript的运行被您禁止了。

Vue2.5.16源码解读二:从入口文件进行阅读

接上回,我们确认了一个入口文件src/platforms/web/entry-runtime-with-compiler.js ,将该文件代码折叠如下图所示,方便一览全局:

可以看到这里import Vue from './runtime/index' 引入了一个Vue ,然后定义了下Vue.prototype.$mount 和Vue.compile ,看Vue源码之前最好是先过一下Vue的官方文档,这里Vue.prototype.$mount 是一个关在Vue原型链上的属性,所以通过new Vue() 创建的Vue的实例都会继承这个$mount 方法,在看这个方法的作用之前,因为看过了官方文档,并且我之前用了两年的Vue了,所以先猜测下这个大概跟Vue组件生命周期里的mounted 钩子可能有关系,可能是这个$mount 方法执行完后就会触发组件生命周期里的mounted 这个钩子里写的程序。现在详细看下相关代码:

const mount = Vue.prototype.$mount
// 返回类型是Component,这个类型下文具体讲,就直译为返回一个组件即可
Vue.prototype.$mount = function (

// el是可选参数,值是字符串(css选择符)或dom元素(Element)

el?: string | Element,

// hydrating也是可选参数,布尔类型,以前用过redux-persist这个库,那里这种名词的意思是是否恢复之前的数据

hydrating?: boolean ): Component {

// 如果el是元素则值维持不变,如果el是字符串则赋值为通过document.querySelector(el)匹配到的元素

el = el && query(el)

// 下面注释里的istanbul指的是一个叫istanbul的代码覆盖率工具

/* istanbul ignore if */

if (el === document.body || el === document.documentElement) {

process.env.NODE_ENV !== 'production' && warn(

// 如果元素是body/document.documentElement,且非针对生产环境打包的话,则提示用户不要将Vue绑定到html或body元素上

`Do not mount Vue to <html> or <body> - mount to normal elements instead.`

)

// 返回this return this }

// 一个$options属性

const options = this.$options // 如果没有定义render函数,则Vue会按下面这样去定义一个render函数

// resolve template/el and convert to render function if (!options.render) {

let template = options.template if (template) {

// 如果有模版

if (typeof template === 'string') {

if (template.charAt(0) === '#') {

// 如果template是一个id选择器(以#开头),则将template重新赋值为对应元素的innerHTML template = idToTemplate(template)

/* istanbul ignore if */

if (process.env.NODE_ENV !== 'production' && !template) {

// 如果id关联到的innerHTML为空或不存在,则在非生产版本下提示用户

warn(

`Template element not found or is empty: ${options.template}`,

this )

}

}

} else if (template.nodeType) {

// 如果template不是字符串,但是有nodeType属性,则判断template为dom,取其innerHTML作为模版

template = template.innerHTML } else {

if (process.env.NODE_ENV !== 'production') {

warn('invalid template option:' + template, this)

}

// 返回this return this }

} else if (el) {

// 如果没有模板但是有元素,就取元素的outerHtml或近似等价的东西

template = getOuterHTML(el)

}

if (template) {

/* istanbul ignore if */

if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

// 通过window.performance.mark来标记性能监测点'compile'

mark('compile')

}

// 获得render和staticRenderFns函数,并挂到Vue.property.$options对象上

const { render, staticRenderFns } = compileToFunctions(template, {

shouldDecodeNewlines,

shouldDecodeNewlinesForHref,

delimiters: options.delimiters,

comments: options.comments }, this)

options.render = render options.staticRenderFns = staticRenderFns

/* istanbul ignore if */

if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

// 通过window.performance.mark标记性能监测点'compile end'

mark('compile end')

// 通过window.erformance.measure来测量compile和compile end这两个性能监测点间的用时

measure(`vue ${this._name} compile`, 'compile', 'compile end')

}

}

}

// 再次调用mount方法

return mount.call(this, el, hydrating)

}

好了,这篇文章对入口文件的分析就写到这里,后续我们将以入口文件为线索展开阅读其他部分的代码。打算看一下Vue.compile = compileToFunctions 这里的compileToFunctions 方法,以及import Vue from './runtime/index' 这里导入的Vue 。

Vue2.5.16源码解读一:确定阅读入口