手机版

Vue源代码分析的Vue实例初始化详细说明

时间:2021-08-20 来源:互联网 编辑:宝哥软件园 浏览:

本节主要记录Vue的初始化过程

以下正式开始:

Vue官网生命周期图

重点关注new Vue()之后的初始化阶段,也就是创建之前发生的事情。

初始生命周期阶段

导出函数initlifetime(VM : Component){ const options=VM。$options //定位第一个非抽象父级让parent=options.parent if (parent!Options.abstract) {while (parent。$ options . abstract parent . $ parent){ parent=parent。$ parent} parent。$ children . push(VM)//将自己添加到父级的$ children array} vm中。$parent=parent //parent组件parent。$root : vm //根组件如果没有父组件,它就是根组件vm。$children=[] //用于存储子组件vm。$refs={} VM。_ Watcher=NullVM。_ Inactive=NullVM。_方向活动=假虚拟机。_ IsMounted=假虚拟机。_ IsDestroyed=假虚拟机。_ ISBEINGDESTROYED=False}接下来是initEvents阶段

//v-on如果写在平台标签上,比如div,会将v-on上注册的事件注册成浏览器事件。//v-on将v-on上注册的事件写入组件标签时,会注册到子组件的事件系统中。//子组件(Vue实例)可能会在初始化期间接收父组件向子组件注册的事件。//子组件(Vue实例)的模板注册的事件在渲染时会根据虚拟DOM//的比较结果来确定。//这里的初始化事件是指父组件在模板中使用v-on注册的事件,添加到子组件的事件系统中,也就是vue的事件系统。导出函数初始化事件(VM :组件){VM。_ events=对象。创建(null)//初始化vm。_hasHookEvent=false //Init父附加事件事件Const侦听器=VM。$期权。_ Parent Listeners If(Listeners){ Update Component Listeners(VM,Listeners)} }导出函数updatecomponent Listeners(VM : Component,listeners: Object,oldListeners:对象){target=VM更新侦听器(侦听器,旧侦听器| | {},添加,删除,createoncehandler,VM) target=undefined}初始化项目阶段

导出函数初始化组件(vm:组件){ //自下而上读取注入常量结果=resolveineject(VM .$options.inject,vm) if (result) { //设置为错误的避免定义活动函数把数据转换为响应式切换观察(假)对象。按键(结果)。forEach(key={ defineReactive(vm,key,result[key]))})//再次更改回来切换观察(真)} }导出函数解析项目(注入:任何,vm:组件):对象{ if (inject) { //inject为:任何,因为流不够智能,无法计算出缓存的常量结果=Object.create(null) //如果浏览器支持符号,则使用Reflect.ownkyes(),否则使用对象。keys()const keys=HASSymbol?反思。拥有密钥(注入):对象。键(注入)用于(让I=0;长度;i ) { const key=keys[i] //#6574以防观察到注入对象.if(key===' _ _ ob _ _ ')continue const provideKey=inject[key].来自信函来源=vm //当提供的注入内容的时候就是把内容注入到当前实例的_已提供中//刚开始的时候来源就是实本身,挡在来源。_已提供中找不到对应的值//就会把来源设置为父实例//Vue实例化的第一步就是规格化用户传入的数据,所以注射不管时数组还是对象//最后都会变成对象while(来源){ if(来源._提供了hasOwn(来源。_提供,提供密钥){ result[key]=source ._提供了{ source=source .$parent } //处理默认值的情况if(!source){ if(' default ' in inject[key]){ const provideDefault=inject[key].默认结果[键]=提供的类型==='函数'?提供默认值。调用(VM): provideDefault } else if(进程。ENV。node _ ENV!==' production '){ warn(' inject ' $ { key } '未找到`,vm) } } }返回结果}}initState阶段

在某视频剪辑软件中,我们经常会用到道具、方法、手表、计算、数据。这些状态在使用前都需要初始化。而初始化的过程正是在初始状态阶段完成。

因为注射是在初始状态之前完成,所以可以在状态中使用注射。

导出函数initState (vm:组件){ vm ._watchers=[] //获取到经过初始化的用户传进来的选项常量选项=vm .$ options if(opts。道具)初始化道具(VM,opts。道具)如果(选择。方法)初始化方法(VM,opts。方法)if(opts。data){ init data(VM)} else { observe(VM ._data={},true/* asRootData */)} if(opts。计算)初始化计算(虚拟机,opts。计算)if(opts。手表选择。看着!==nativeWatch) { initWatch(vm,opts.watch) }}initProps

函数initProps (vm:组件,props :对象){ const Propsdata=VM .$选项。propsdata | | { } const props=VM ._道具={} //缓存支柱键,以便将来的支柱更新可以使用数组/而不是动态对象键枚举进行迭代。//缓存小道具的键值常量键=vm .$选项_propKeys=[] const isRoot=!虚拟机$parent //应该转换根实例道具/如果不是跟组件则没必要转换成响应式数据if(!isRoot) { //控制是否转换成响应式数据切换观察(假)}为(性能)中的const key){ keys。按(键)//获取小道具的值const value=validateProp(key,propsOptions,propsData,VM)define active(props,key,value) //静态小道具已经在组件的原型//上进行了代理,在Vue.extend()期间。我们只需要在//实例化这里定义代理道具。//把小道具代理到某视频剪辑软件实例上来,可以直接通过这个道具访问if(!(键在伏特计中)){代理(vm,` _props `,键)} }切换观察(真)}初始化方法

函数initMethods (vm:组件,methods :对象){ const props=VM .$选项。方法中的常量键的道具。ENV。NODE _ ENV!=='production') { //如果键不是一个函数报错if (typeof methods[key]!==' function '){ warn(' method ' $ { key } '在组件定义中具有类型${typeof methods[key]} ' .` `您是否正确引用了该函数?`,vm ) } //如果小道具中存在同名的属性报错if (props hasOwn(props,key)) { warn(`Method '${key})已经定义为道具。`,vm ) } //isReserved判断是否以$或_开头如果((vm中的键)是保留的(键)){ warn(`Method '${key} '与现有的某视频剪辑软件实例方法冲突。` `避免定义以_或$ .`)开头的组件方法} } //把方法的方法绑定到某视频剪辑软件实例上vm[key]=typeof methods[key]!=='函数?noop : bind(methods[key],vm) }}initData

函数initData (vm:组件){ 0让数据=vm .$options.data data=vm ._数据=数据类型==='函数'?getData(data,VM): data | | { }//isplaynobject监测数据是不是对象if(!isplaynobject(data)){ data={ }进程。ENV。node _ ENV!==“生产”警告(数据函数应该返回一个对象: \ n ' ' https://vuejs。组织/v2/指南/组件。html #数据必须是函数',vm ) } //实例const key=对象。密钥(数据)常量道具=虚拟机上的代理数据$options .道具常量方法=vm .$options.methods让i=keys.length //循环数据while(I-){ const key=keys[I]if(进程。ENV。NODE _ ENV!=='production') { //如果在方法中存在和键同名的属性则报错if (methods hasOwn(methods,key)) { warn(`Method '${key})已经被定义为数据属性.`,vm ) } } //如果在小道具中存在和键同名的属性则报错if (props hasOwn(props,key)) { process.env.NODE_ENV!==“生产”警告(`数据属性“${key}”已声明为一个道具。` `请改用正确的默认值`,vm ) }否则如果(!is retried(key)){//is retried判断是否以$或_开头//代理数据,使得可以直接通过这把钥匙访问这个_data.key代理(vm,` _data `,key) } } //观察数据/把数据转换为响应式数据观察(数据,true/* as root data */)} init computed

const computed watchero options={ lazy : true }函数init computed(VM : Component,computed : Object){//$ flow-disable-line const watchers=VM ._计算观察者=对象。创建(null)//计算出的属性只是苏维埃社会主义共和国期间的获取者/判断是不是服务端渲染const isSSR=isserveryrinthinding()for(const key in computed){ const userDef=computed[key]const getter=userDef的类型===' function '?userDef : userDef。get if(process。ENV。node _ ENV!==“production”getter==null){ warn(` 0计算属性“${key}”缺少吸气器。`,vm ) } //如果不是ssr,则创建看守人实例if(!isSSR) { //为计算属性创建内部观察器watchers[key]=new watchers(VM,getter || noop,noop,computedwatcherooptions)}//组件定义的计算属性已经在//组件原型上定义。我们只需要在实例化时定义计算属性//。//如果伏特计不存在键的同名属性if(!(虚拟机中的键){ defineComputed(vm,键,UserDef)} else if(process。ENV。NODE _ ENV!==“生产”){如果(虚拟机中的键$ data){ warn(` 0计算属性“${key}”已在数据。`,vm) } else if (vm .$ options .道具中的道具密钥$options.props) { warn(`计算属性“${key}”已经定义为道具。`,VM)} } } }共享属性定义={可枚举: true,cn推测:true,get: noop,set: noop }导出函数defineComputed (target: any,key: string,user def : Object | Function){//如果是服务端渲染,则计算不会有缓存,因为数据响应式的过程在服务器是多余的const shouldCache=!is serverending()//createComputedGetter返回计算属性的getter//creategetinvoker返回户自定义的getter if(类型为UserDef==' function '){ shared property tdefinition。get=应该缓存吗?createComputedGetter(key): creategetinvoker(UserDef)shared propertyttdefinition。set=noop } else {//当户自定义为一个对象时共享属性定义。get=UserDef。明白吗?应该缓存userDef.cache!==假的?createComputedGetter(key): creategetinvoker(user def。get): noop sharedpropertytdefinition。set=userdef。set | | noop } if(过程。ENV。node _ ENV!==“production”共享属性定义。set===noop){ sharedpropertyteddefinition。set=function(){ warn(` computed property ' $ { key } '已分配给,但它没有塞特。`,这个)} } //在眼泪上定义一个属性,属性名为关键,属性描述符为sharedpropertytdefinition对象。定义属性(目标,键,sharedpropertyteddefinition)}函数createComputedGetter(键){返回函数computedGetter () { //查找是否存在键的观察者常量观察者=这个_计算观察者这_ computed watchers[key]if(watcher){//如果肮脏的为没错,则重新计算,否则返回缓存if(观察者。dirty){ watcher。评估()} if(Dep。target){ watcher。depend()}返回观察器。值} } }函数creategetinvoker(fn){ return函数computedGetter(){ return fn。调用(这个,这个)}}initWatch

函数initWatch (vm:组件手表:对象){ for(watch中的常数键){ const handler=watch[key] //处理数组类型if (Array.isArray(处理程序)){ for(让I=0;I handler . lenti){ createWatcher(VM,key,handler[I])} } else { createWatcher(VM,key,handler)} } Function createWatcher(VM : Component,expOrFn: string | Function,handler:有没有,选项?对象){//isplayanoobject检查是否是对象if(isplayanoobject(handler)){ options=handler=handler。处理程序} if(处理程序的类型===' string '){ handler=VM[handler]}//最后调用$手表返回虚拟机$watch(expOrFn,处理程序,选项)}initProvide阶段

导出函数init provide (vm:组件){const provide=vm。$选项。提供if(provide){//保存提供给_provided vm。_ provided=provide==' function '的类型?Provide.call(vm) : provide }}这里,Vue的初始化结束,然后触发创建的生命周期函数。

总结一下:执行new Vue()后,Vue进入初始化阶段。

初始化过程如下:

规范化$选项,即用户定义的数据initLifecycle注入生命周期initEvents初始化事件,注意:这里的事件是其值由子组件上的父组件定义的事件。初始化渲染初始化项目初始化操作初始化道具初始化道具初始化状态包括道具、方法、数据、计算、观察初始化提供初始化提供摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。

版权声明:Vue源代码分析的Vue实例初始化详细说明是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。