You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// /src/platforms/web/entry-runtime-with-compiler.js/* @flow */importconfigfrom'core/config'import{warn,cached}from'core/util/index'import{mark,measure}from'core/util/perf'importVuefrom'./runtime/index'import{query}from'./util/index'import{compileToFunctions}from'./compiler/index'import{shouldDecodeNewlines,shouldDecodeNewlinesForHref}from'./util/compat'constidToTemplate=cached(id=>{constel=query(id)returnel&&el.innerHTML})constmount=Vue.prototype.$mountVue.prototype.$mount=function(el?: string|Element,hydrating?: boolean): Component{el=el&&query(el)/* istanbul ignore if */if(el===document.body||el===document.documentElement){process.env.NODE_ENV!=='production'&&warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`)returnthis}constoptions=this.$options// resolve template/el and convert to render functionif(!options.render){lettemplate=options.templateif(template){if(typeoftemplate==='string'){if(template.charAt(0)==='#'){template=idToTemplate(template)/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&!template){warn(`Template element not found or is empty: ${options.template}`,this)}}}elseif(template.nodeType){template=template.innerHTML}else{if(process.env.NODE_ENV!=='production'){warn('invalid template option:'+template,this)}returnthis}}elseif(el){template=getOuterHTML(el)}if(template){/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){mark('compile')}const{ render, staticRenderFns }=compileToFunctions(template,{outputSourceRange: process.env.NODE_ENV!=='production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,delimiters: options.delimiters,comments: options.comments},this)options.render=renderoptions.staticRenderFns=staticRenderFns/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){mark('compile end')measure(`vue ${this._name} compile`,'compile','compile end')}}}returnmount.call(this,el,hydrating)}/** * Get outerHTML of elements, taking care * of SVG elements in IE as well. */functiongetOuterHTML(el: Element): string{if(el.outerHTML){returnel.outerHTML}else{constcontainer=document.createElement('div')container.appendChild(el.cloneNode(true))returncontainer.innerHTML}}Vue.compile=compileToFunctionsexportdefaultVue
// /src/platforms/web/runtime/index.js/* @flow */importVuefrom'core/index'importconfigfrom'core/config'import{extend,noop}from'shared/util'import{mountComponent}from'core/instance/lifecycle'import{devtools,inBrowser}from'core/util/index'import{query,mustUseProp,isReservedTag,isReservedAttr,getTagNamespace,isUnknownElement}from'web/util/index'import{patch}from'./patch'importplatformDirectivesfrom'./directives/index'importplatformComponentsfrom'./components/index'// install platform specific utilsVue.config.mustUseProp=mustUsePropVue.config.isReservedTag=isReservedTagVue.config.isReservedAttr=isReservedAttrVue.config.getTagNamespace=getTagNamespaceVue.config.isUnknownElement=isUnknownElement// install platform runtime directives & componentsextend(Vue.options.directives,platformDirectives)extend(Vue.options.components,platformComponents)// install platform patch functionVue.prototype.__patch__=inBrowser ? patch : noop// public mount methodVue.prototype.$mount=function(el?: string|Element,hydrating?: boolean): Component{el=el&&inBrowser ? query(el) : undefinedreturnmountComponent(this,el,hydrating)}// devtools global hook/* istanbul ignore next */if(inBrowser){setTimeout(()=>{if(config.devtools){if(devtools){devtools.emit('init',Vue)}elseif(process.env.NODE_ENV!=='production'&&process.env.NODE_ENV!=='test'){console[console.info ? 'info' : 'log']('Download the Vue Devtools extension for a better development experience:\n'+'https://github.com/vuejs/vue-devtools')}}if(process.env.NODE_ENV!=='production'&&process.env.NODE_ENV!=='test'&&config.productionTip!==false&&typeofconsole!=='undefined'){console[console.info ? 'info' : 'log'](`You are running Vue in development mode.\n`+`Make sure to turn on production mode when deploying for production.\n`+`See more tips at https://vuejs.org/guide/deployment.html`)}},0)}exportdefaultVue
// /src/core/instance/index.jsimport{initMixin}from'./init'import{stateMixin}from'./state'import{renderMixin}from'./render'import{eventsMixin}from'./events'import{lifecycleMixin}from'./lifecycle'import{warn}from'../util/index'functionVue(options){if(process.env.NODE_ENV!=='production'&&!(thisinstanceofVue)){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)exportdefaultVue
可以看到,这里就是我们要找的定义 Vue 函数的地方了。函数体内第一段逻辑是如果用户调用 Vue 的时候没有使用 new 操作符,就会抛出一个警告。然后又调用了 _init 方法,这个方法没有在这里被定义,显然是继承来的。
// /src/core/index.jsimportVuefrom'./instance/index'import{initGlobalAPI}from'./global-api/index'import{isServerRendering}from'core/util/env'import{FunctionalRenderContext}from'core/vdom/create-functional-component'initGlobalAPI(Vue)Object.defineProperty(Vue.prototype,'$isServer',{get: isServerRendering})Object.defineProperty(Vue.prototype,'$ssrContext',{get(){/* istanbul ignore next */returnthis.$vnode&&this.$vnode.ssrContext}})// expose FunctionalRenderContext for ssr runtime helper installationObject.defineProperty(Vue,'FunctionalRenderContext',{value: FunctionalRenderContext})Vue.version='__VERSION__'exportdefaultVue
// /src/core/global-api/index.js/* @flow */importconfigfrom'../config'import{initUse}from'./use'import{initMixin}from'./mixin'import{initExtend}from'./extend'import{initAssetRegisters}from'./assets'import{set,del}from'../observer/index'import{ASSET_TYPES}from'shared/constants'importbuiltInComponentsfrom'../components/index'import{observe}from'core/observer/index'import{warn,extend,nextTick,mergeOptions,defineReactive}from'../util/index'exportfunctioninitGlobalAPI(Vue: GlobalAPI){// configconstconfigDef={}configDef.get=()=>configif(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=setVue.delete=delVue.nextTick=nextTick// 2.6 explicit observable APIVue.observable=<T>(obj: T): T =>{observe(obj)returnobj}
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)
}
接着下面又定义了 util,注意这里的注释:these are not considered part of the public API - avoid relying on them unless you are aware of the risk。也就说 util 这个属性不是公共 api,官网文档没有这个属性的介绍,建议不要去依赖这个属性除非能够预知风险。
前言
我们在使用 Vue 的时候,要先使用
new
运算符调用 Vue,也就是说 Vue 是一个构造函数。在正式进入源码学习前,先在直观上了解 Vue 这个构造函数的样子。回顾上一节 Vue.js 源码构建 ,通过
scripts
目录下的config.js
和alias.js
,我们可以查到构建出 Vue 完整版的入口文件路径为/src/platforms/web/entry-runtime-with-compiler.js
。Vue 构造函数
找到构建 Vue 的入口文件后,看看它长什么样:
可以看到这里引入了 Vue 又将其导出,所以入口文件并不是定义 Vue 函数的地方。可以看到入口文件的作用有两个,一是重写了 Vue 函数的原型上的
$mount
函数,二是添加了全局函数compileToFunctions
。继续往上找,来到/src/platforms/web/runtime/index.js
,代码如下:这个文件同样不是定义 Vue 函数的地方,这里在 Vue 构造函数的原型上定义了
$mount
,同时往Vue.config
和Vue.options
上添加方法。继续往上找,来到/src/core/index.js
:省略了中间代码,等下再回来分析。这里依然不是,继续找,来到
/src/core/instance/index.js
:可以看到,这里就是我们要找的定义 Vue 函数的地方了。函数体内第一段逻辑是如果用户调用 Vue 的时候没有使用
new
操作符,就会抛出一个警告。然后又调用了_init
方法,这个方法没有在这里被定义,显然是继承来的。之后将 Vue 这个构造函数作为参数传给了另外五个函数,推断这五个函数功能类似,先来看第一个
initMixin
:initMixin
就是往 Vue 的原型挂载刚刚提到的_init
方法,大致就是内部初始化的过程,这里不研究具体代码,放在下一节研究。另外四个函数也一样,都是往
Vue.prototype
上挂载属性和方法,这里不深入研究。本章是入门篇,在于大致地了解 Vue 构造函数的样子,这五个函数分别挂载了什么函数将放在后面深入讲解。把 Vue 构造函数所在的
/src/core/instance/index.js
文件研究完后,回到上一级,也就是/src/core/index.js
,下面是完整代码:这里引入了构造函数 Vue 后作为参数传给
initGlobalAPI
这个函数。之后又在 Vue.prototype 上添加了几个属性。现在来看看initGlobalAPI
,这个函数在/src/core/global-api/index.js
中:看函数的名称推断出就是给 Vue 构造函数定义全局(静态)的属性和函数上去。
这里创建一个
configDef
代理了Vue.config
,并且在非生产环境下如果尝试修改config
,会抛出一个警告。接着下面又定义了
util
,注意这里的注释:these are not considered part of the public API - avoid relying on them unless you are aware of the risk
。也就说util
这个属性不是公共 api,官网文档没有这个属性的介绍,建议不要去依赖这个属性除非能够预知风险。之后又在 Vue 上定义了多个属性和方法,然后调用
extend
方法,最后又将 Vue 作为参数传给四个函数,这四个函数都是在 Vue 上创建静态函数,例如Vue.use
等.来看看这个
extend
函数,这个方法定义在/src/shared/util.js
里,瞄一眼:其实就是把
builtInComponents
的所有属性混合到Vue.options.components
对应属性上。这个
builtInComponents
来自/src/core/components/index.js
:builtInComponents
就是Keep-Alive
这个组件。总结
以上,我们把从入口文件一直到定义 Vue 构造函数的基本流程梳理了一遍。整个过程就是定义 Vue 构造函数,然后给 Vue 定义全局(其实就是静态)的属性和方法,同时又定义了 Vue.prototype(其实就是给实例用的)上的属性和方法。这些属性和方法有一部分是暴露给用户使用的,也就是在 Vue 官方文档上能找到的。
Vue 构造函数全局的和原型上的属性和方法在本文没有细讲,这些属性和方法的原理和用途会放在后面细细研究。
下一节:从一个小例子开始
The text was updated successfully, but these errors were encountered: