这篇“vue初始化要做什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue初始化要做什么”文章吧。 做的事:1、选项合并,处理组件的配置内容;2、初始化vue实例生命周期相关的属性;3、初始化自定义组件事件的监听;4、初始化render渲染所需的slots、渲染函数等;5、调用beforeCreate函数;6、初始化注入数据;7、对props、data、watch等进行初始化;8、把祖辈传下的数据注入后初始化provide;9、调用created函数;10、挂载DOM元素。在创建之前首先会有一些混入的方法,用于初始化实例的方法和属性initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
这里先看initMixin就行initMixin方法的作用是混入Vue的_init
方法,_init
方法里的核心又是以下方法合并options配置initLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, ‘beforeCreate’)initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, ‘created’)
vm.$options=mergeOptions(//合并options resolveConstructorOptions(vm.constructor), options||{}, vm )
合并options并在实例上挂载一个$options属性。合并什么东西了?这里是分两种情况的:
初始化new Vue在执行new Vue
构造函数时,参数就是一个对象,也就是用户的自定义配置;会将它和vue
之前定义的原型方法,全局API属性;还有全局的Vue.mixin
内的参数,将这些都合并成为一个新的options
,最后赋值给一个的新的属性$options
。子组件初始化如果是子组件初始化,除了合并以上那些外,还会将父组件的参数进行合并,如有父组件定义在子组件上的event
、props
等等。经过合并之后就可以通过this.$options.data
访问到用户定义的data函数,this.$options.name
访问到用户定义的组件名称,这个合并后的属性很重要,会被经常使用到。主要作用是确认组件的父子关系和初始化某些实例属性。
exportfunctioninitLifecycle(vm:Component){ constoptions=vm.$options//之前免费云主机、域名合并的属性 letparent=options.parent; if(parent&&!options.abstract){//找到第一个非抽象父组件 while(parent.$options.abstract&&parent.$parent){ parent=parent.$parent } parent.$children.push(vm) } vm.$parent=parent//找到后赋值 vm.$root=parent?parent.$root:vm//让每一个子组件的$root属性都是根组件 vm.$children=[] vm.$refs={} vm._watcher=null ... vm._isDestroyed=false vm._isBeingDestroyed=false }
初始化自定义组件事件的监听,若存在父监听事件,则添加到该实例上。
主要作用是将父组件在使用v-on或@注册的自定义事件添加到子组件的事件中心中。
exportfunctioninitEvents(vm:Component){ vm._events=Object.create(null)//事件中心 vm._hasHookEvent=false //initparentattachedevents constlisteners=vm.$options._parentListeners//经过合并options得到的 if(listeners){ updateComponentListeners(vm,listeners) } }
初始化render渲染所需的slots、渲染函数等。其实就两件事。
1、插槽的处理、
2、$createElm 也就是 render 函数中的 h 的声明
exportfunctioninitRender(vm){ vm._vnode=null ... vm._c=(a,b,c,d)=>createElement(vm,a,b,c,d,false)//转化编译器的 vm.$createElement=(a,b,c,d)=>createElement(vm,a,b,c,d,true)//转化手写的 ... }
调用 beforeCreate
钩子函数。现在这里只需要知道它会执行用户自定义的生命周期方法,如果有mixin混入的也一并执行。相关面试题:请问可以在beforeCreate钩子内通过this访问到data中定义的变量么,为什么以及请问这个钩子可以做什么?> 回答:是不可以访问的,因为在vue初始化阶段,这个时候data中的变量还没有被挂载到this上,这个时候访问值会是undefined。beforeCreate这个钩子在平时业务开发中用的比较少,而像插件内部的instanll方法通过Vue.use方法安装时一般会选在beforeCreate这个钩子内执行,vue-router和vuex就是这么干的。后面的初始化顺序是inject => state => provide
初始化inject在props/data之前,这样做的目的是可以在props/data中使用inject内所注入的内容
exportfunctioninitInjections(vm:Component){ constresult=resolveInject(vm.$options.inject,vm) if(result){ toggleObserving(false)//刻意为之不被响应式 Object.keys(result).forEach(key=>{ ... defineReactive(vm,key,result[key]) }) toggleObserving(true) } }
resolveInject的主要作用就是自下而上的一层一层的找当前被注入的数据
exportfunctionresolveInject(inject:any,vm:Component):?Object{ if(inject){ //injectis:anybecauseflowisnotsmartenoughtofigureoutcached //首先定义一个result返回找到的结果。 constresult=Object.create(null) constkeys=hasSymbol ?Reflect.ownKeys(inject) :Object.keys(inject) //接下来使用双循环查找,外层的for循环会遍历inject的每一项 for(leti=0;i
初始化会被使用到的状态,状态包括props,methods,data,computed,watch五个选项。(这里先看props,methods,data)
exportfunctioninitState(vm:Component){ vm._watchers=[] constopts=vm.$options if(opts.props)initProps(vm,opts.props) if(opts.methods)initMethods(vm,opts.methods) if(opts.data){ initData(vm) }else{ observe(vm._data={},true/*asRootData*/) } if(opts.computed)initComputed(vm,opts.computed) if(opts.watch&&opts.watch!==nativeWatch){ initWatch(vm,opts.watch) } }
主要作用是检测子组件接受的值是否符合规则,以及让对应的值可以用this直接访问
functioninitProps(vm:Component,propsOptions:Object){//第二个参数为验证规则 constpropsData=vm.$options.propsData||{}//props具体的值父组件传过来的 constprops=vm._props={}//存放props组件内可以通过这个访问到传过来的props constisRoot=!vm.$parent//是否是根节点 if(!isRoot){//不是根节点则关闭响应式 toggleObserving(false) } for(constkeyinpropsOptions){ constvalue=validateProp(key,propsOptions,propsData,vm) defineReactive(props,key,value) if(!(keyinvm)){ proxy(vm,`_props`,key)//代理this.xx实际上访问的是this._props.xx } } toggleObserving(true) }
主要作用是将methods内的方法挂载到this下。
functioninitMethods(vm:Component,methods:Object){ constprops=vm.$options.props for(constkeyinmethods){ if(methods[key]==null){//methods[key]===null||methods[key]===undefined的简写 warn(`只定义了key而没有相应的value`) } if(props&&hasOwn(props,key)){ warn(`方法名和props的key重名了`) } if((keyinvm)&&isReserved(key)){ warn(`方法名已经存在而且以_或$开头`) } vm[key]=typeofmethods[key]!=='function'?noop:bind(methods[key],vm)//相当于methods[key].bind(vm) } }
functioninitData(vm:Component){ letdata=vm.$options.data data=vm._data=typeofdata==='function' ?getData(data,vm) :data||{} if(!isPlainObject(data)){ data={} } //proxydataoninstance constkeys=Object.keys(data) constprops=vm.$options.props constmethods=vm.$options.methods leti=keys.length while(i--){ constkey=keys[i] if(methods&&hasOwn(methods,key)){ warn(`和methods内的方法重名了`) } if(props&&hasOwn(props,key)){ warn(`和props内的key重名了`) }elseif(!isReserved(key)){//key不能以_或$开头 proxy(vm,`_data`,key) } } //observedata observe(data,true/*asRootData*/) }
很容易看出是把用户传进来的provide
选项先获取到,如果是方法则执行一下再挂载到实例的_provided
属性,不是则直接挂载到_provided
属性
exportfunctioninitProvide(vm:Component){ constprovide=vm.$options.provide if(provide){ vm._provided=typeofprovide==='function' ?provide.call(vm) :provide } }
调用 created
钩子函数1、选项合并,处理组件的配置内容,将传入的options与构造函数本身的options进行合并(用户选项和系统默认的选项进行合并)2、初始化vue实例生命周期相关的属性,定义了比如:root、root、root、parent、children、children、children、refs3、初始化自定义组件事件的监听,若存在父监听事件,则添加到该实例上4、初始化render渲染所需的slots、渲染函数等。其实就两件事:插槽的处理 和 $createElm
的声明,也就是 render 函数中的 h 的声明5、调用 beforeCreate 钩子函数,在这里就能看出一个组件在创建前和后分别做了哪些初始化6、初始化注入数据,隔代传参时 先inject。作为一个组件,在要给后辈组件提供数据之前,需要先把祖辈传下来的数据注入进来7、对props,methods,data,computed,watch进行初始化,包括响应式的处理8、在把祖辈传下来的数据注入进来以后 再初始化provide9、调用 created 钩子函数,初始化完成,可以执行挂载了10、挂载到对应DOM元素上。如果组件构造函数设置了el选项,会自动挂载,所以就不用再手动调用$mount去挂载。以上就是关于“vue初始化要做什么”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注云技术行业资讯频道。
这篇文章主要讲解了“JavaScript中的声明提升是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript中的声明提升是什么”吧!声明提升(hosting)是 JavaScript 解析器的一…