当前位置: 首页 > Web前端 > vue.js

从入门开始

时间:2023-03-31 17:14:47 vue.js

从入门我们之前提到了Vue.js的构建过程。在web应用下,我们来分析一下Runtime+Compiler构建的Vue.js。它的条目是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)/*伊斯坦布尔忽略if*/if(el===document.body||el===document.documentElement){process.env.NODE_ENV!=='production'&&warn(`不要将Vue挂载到或-挂载到普通元素stead.`)returnthis}constoptions=this.$options//解析模板/el并转换为渲染函数if(!options.render){lettemplate=options.templateif(template){if(typeoftemplate==='string'){if(template.charAt(0)==='#'){template=idToTemplate(template)/*伊斯坦布尔忽略if*/if(process.env.NODE_ENV!=='production'&&!template){warn(`Templateelementnotfoundorisempty:${options.template}`,this)}}elseif(template.nodeType){template=template.innerHTML}else{if(process.env.NODE_ENV!=='production'){warn('invalidtemplateoption:'+template,this)}returnthis}}elseif(el){template=getOuterHTML(el)}if(template){/*istanbulignoreif*/if(process.env.NODE_ENV!=='生产'&&config.performance&&mark){mark('compile')}const{render,staticRenderFns}=compileToFunctions(template,{shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters:options.delimiters,comments:options.comments},this)选项.render=renderoptions.staticRenderFns=staticRenderFns/*istanbul忽略if*/if(process.env.NODE_ENV!=='production'&&config.performance&&mark){mark('compileend')measure(`vue${this._name}compile`,'compile','compileend')}}}returnmount.call(this,el,hydrating)}/***获取元素的outerHTML,同时注意IE中的SVG元素。*/functiongetOuterHTML(el:Element):string{if(el.outerHTML){returnel.outerHTML}else{constcontainer=document.createElement('div')container.appendChild(el.cloneNode(true))返回容器.innerHTML}}Vue.compile=compileToFunctionsexportdefaultVue那么我们的代码在执行importVuefrom'vue'的时候,就是从这个入口执行代码来初始化Vue,那么Vue是什么,是怎么初始化的,我们来看看Vue的入口在入口JS上面,我们可以找到Vue的源码:importVuefrom'./runtime/index',我们看一下这块的实现,定义在src/platforms/web/runtime/indexIn.js:importVuefrom'core/index'importconfigfrom'core/config'import{extend,noop}from'shared/util'import{mountComponent}from'core/instance/lifecycle'import{devtools,inBrowser,isChrome}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'//安装特定平台utilsVue.config.mustUseProp=mustUsePropVue.config.isReservedTag=isReservedTagVue.config.isReservedAttr=isReservedAttrVue.config.getTagNamespace=getTagNamespaceUownnk/isUnmentle=getTagNamespaceUownnk/isUnmentle=安装平台运行时指令和组件扩展(Vue.options.directives,platformDirectives)extend(Vue.opoptions.components,platformComponents)//安装平台补丁functionVue.prototype.__patch__=inBrowser?patch:noop//publicmountmethodVue.prototype.$mount=function(el?:string|Element,hydrating?:boolean):Component{el=el&&inBrowser?query(el):undefinedreturnmountComponent(this,el,hydrating)}//...exportdefaultVue这里关键代码是importVuefrom'core/index',后面的逻辑就可以了Vue对象有一些扩展,所以你不需要先看它。我们来看看真正初始化Vue的地方。在src/core/index.js中:importVuefrom'./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忽略下一个*/returnthis.$vnode&&this.$vnode.ssrContext}})//公开FunctionalRenderContextforssrruntimehelperinstallationObject.defineProperty(Vue,'FunctionalRenderContext',{value:FunctionalRenderContext})Vue.version='__VERSION__'exportdefaultVue这里有2个关键代码,importVuefrom'./instance/index'andinitGlobalAPI(Vue),初始化全局VueAPI(后面会介绍),我们先看第一部分,在src/core/instance/index.js中:Vue的定义import{initMixin}from'./init'从'./state'导入{stateMixin}从'./render'导入{renderMixin}从'./events'导入{lifecycleMixin}从'./lifecycle'导入{warn}从'../util/index'functionVue(options){if(process.env.NODE_ENV!=='production'&&!(thisinstanceofVue)){warn('Vue是一个构造函数,应该使用`new`关键字调用')}this._init(options)}initMixin(Vue)stateMixin(Vue)eventsMixin(Vue)lifecycleMixin(Vue)renderMixin(Vue)exportdefaultVue到这里,我们终于看到了Vue的真面目,它其实是一个函数实现mented类,我们只能通过newVue实例化它有同学看到这里不禁疑惑,为什么Vue不使用ES6Class来实现呢?我们回过头来看,这里调用了很多xxxMixin函数,并且传入了Vue作为参数。它们的作用是在Vue的原型上扩展一些方法(这里的具体细节会在后面的文章中介绍,这里不再展开)。Vue将这些扩展分散到多个模块中去实现功能,而不是全部在一个模块中实现,而Class很难实现。这样做的好处是非常方便代码的维护和管理,而且这种编程技巧也非常值得学习。InitGlobalAPIVue.js在整个初始化过程中,除了在其prototype原型上扩展方法外,还会将全局静态方法扩展到Vue对象本身,定义在src/core/global-api/index.js中:exportfunctioninitGlobalAPI(Vue:GlobalAPI){//configconstconfigDef={}configDef.get=()=>configif(process.env.NODE_ENV!=='production'){configDef.set=()=>{warn('不要替换Vue.config对象,而是设置单独的字段。')}}Object.defineProperty(Vue,'config',configDef)//暴露的util方法。//注意:这些不被视为公共API的一部分-除非您意识到风险,否则请避免依赖它们。Vue.util={warn,extend,mergeOptions,defineReactive}Vue.set=setVue.delete=delVue.nextTick=nextTickVue.options=Object.create(null)ASSET_TYPES.forEach(type=>{Vue.options[type+'s']=Object.create(null)})//这用于标识“基础”构造函数以扩展所有普通对象//W中的组件eex的多实例场景。Vue.options._base=Vueextend(Vue.options.components,builtInComponents)initUse(Vue)initMixin(Vue)initExtend(Vue)initAssetRegisters(Vue)}下面是在Vue上扩展的一些全局方法全局API上的定义Vue官网可以在这里找到,这里就不详细介绍了。我们在后面的章节介绍某个API的时候会详细介绍。需要注意的一点是,暴露的Vue.util方法最好不要依赖,可能会经常变化,不稳定。至此,基本介绍了Vue的初始化流程。本节的目的是让学生对Vue是什么有一个直观的认识。它本质上是一个用Function实现的Class,其原型prototype和自身扩展了一系列的方法和属性。那么Vue能做什么,是怎么做到的,我们将在后面的章节中一层层帮你揭开Vue的神秘面纱。