ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 生命周期钩子函数 Vue初始化主要就干了几件事:**合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化data、props、computed、watcher等**。 ![](https://box.kancloud.cn/4d2592b327b1dbe78cc1b8b9a58677cc_443x654.png) ![](https://box.kancloud.cn/45962e16d4dd4450d1b04a1871bc4e25_522x443.png) 每个Vue实例在被创建时都要经历一系列的初始化过程。 例如:**从开始创建、初始化数据、模板编译、挂载dom、数据变化时更新dom,卸载等一系列过程**。这一系列过程就是vue的生命周期。 Vue实例有一个完整的声明周期,也就是从开始创建、初始化数据、编译模板、挂载DOM--》渲染,更新==》渲染,卸载等一系列过程,这就是vue的声明周期。通俗说就是**Vue实例从创建到销毁的过程**,就是生命周期。 ### **new Vue()之后** 实例化Vue对象,开始初始化,初始化事件和生命周期(init Events & init Lifecycle)。 * 合并options(自定义属性,data函数成员,methods对象成员,模板template,挂载元素el、生命周期钩子、props属性声明、computed计算成员、watch监视成员等) 两个来源:一个是Vue的构造函数(parent)一个是new Vue传入的child,最终生成统一的options(父子组件) ![](https://box.kancloud.cn/a57e65babbb3f14b3fce03a8648a046e_459x192.png) * initProxy(vm)//代理vm属性 * initLifecycle(vm):初始化一些和声明周期相关的内容 ![](https://box.kancloud.cn/93e428caad0c8425677b06c08659b3a3_826x411.png) * initEvents:存储父组件绑定当前子组件的事件,保存到vm._events ![](https://box.kancloud.cn/a86e0938eb18d80adc5bc704e9dc2c2a_227x52.png) * initRender:初始化render函数,定义vm._c和vm.$createElement等方法 ![](https://box.kancloud.cn/46c45fd54da43cb772b5e9c3418e6561_255x54.png) 调用beforeCreate ### **beforeCreate之后**: * 完成实例初始化,初始化非响应式变量 * this执行创建的实例 * 可以在这家loading事件; * data,computed,watch,methods上的方法和数据均不能访问。 * 此时还没有el选项(created的时候数据已经和data属性进行绑定) * 是获取不到props或者data中的数据的,因为这些数据的**初始化都在initState中** 组件刚被创建,组件属性计算之前,如data属性等。(在实例初始化之后,**数据观测(data observer)和event/watcher事件配置之前被调用**) ~~~ initInjections(vm) // resolve injections before data/props initState(vm) // 初始化数据,进行双向绑定 state/props initProvide(vm) // resolve provide after data/props 注入provider的值到子组件中 ~~~ **initInjections和initProvide:通过逐级查找,从父级provide中获取子级组件inject定义的属性值,并增加对该属性的监听**。通过依赖注入导入依赖项。 initState: **initProps=》initData =》initComputed=》initWatch** ![](https://box.kancloud.cn/ca73f8631a44375df10883a5e182e29b_193x124.png) 调用created ### **created之后** 组件实例创建完成,属性已绑定,此时DOm还未生成。这一步,实例已完成一下的配置(数据观测data observer,属性和方法的运算,watch/event事件回调,挂载还没开始,$el还不可见) * 实例创建完成 * 完成数据(data props computed)的初始化 导入依赖项 * 可访问data computed watch methods上的方法和数据 * 未挂载dom,不能访问$el,$ref为空数组 * 可在这结束loading,还做一些初始化,实现函数自执行 * 可对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长 * 若在此阶段进行DOM操作,一定要放在Vue.nexTick()的回调函数中。 el属性:检查vue配置,el项是否存在,template项 (对象和事件已完全初始化)(已数据绑定)首先判断对象是否有**el选项,有的话就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,知道该vue实例上调用vm.$mount(el)**(遇到vm.$mount(el)代码会继续向下执行,否则停止) ~~~ el: '#app' ~~~ **template参数选项的有无对生命周期的影响**。 1. 如果vue实例对象有template选项,则将其作为模板编译成render函数 2. 如果没有template选项,则将**外部的HTML作为模板编译** 所以el判断要做template之前,因为vue需要通过el判断对应的outer template。 ~~~ <div id="app"> <!--html中修改的--> <h1>{{message + '这是在outer HTML中的'}}</h1> </div> ~~~ ~~~ var vm = new Vue({ el: '#app', template: "<h1>{{message +'这是在template中的'}}</h1>", //在vue配置项中修改的 data: { message: 'Vue的生命周期' } ~~~ 在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX ~~~ new Vue({ el: '#app', render: function(createElement) { return createElement('h1', 'this is createElement') } }) ~~~ 所以综合排名优先级 render函数选项>template选项>outer HTML 此时vm.$le打印的是undefined ### **beforeMounted之后** **开始创建vdom** * 有了el,编译了template/outerHTML * 能找到对应的template,并编译成render函数 模板编译、挂载之前:相关的render函数首次被调用 **create vm.$el and replace 'el' width it**:编译,并替换了被绑定元素。 * html字符串提取,无论是el还是template,最后都是提取html的字符串 * 编译,将html的字符串编译成AST抽象树,在拼接成render表达式 * 形成真是的dom,render转为vnode,最终生成时间的dom,并增加更新的监听 Vue中$mount出现在两个文件中,前一个文件,会将普通的**template字符串转换成render语法**,然后**调用后一个文件中的mount,完成dom的呈现**。 完整的挂载过程: 1. 执行beforeMount回调方法 2. 定义updateComponent放,vm.\_render,实现将render表达式转为vnode,vm.\_update将vnode渲染成实际的dom 3. 构建watcher实例,两个作用 * 执行updateComponent方法,实现dom的渲染,并完成**表达式对属性变量的依赖收集**。 * 一旦包含的表达式中的属性变量有变化,将重新执行update。 4. 判断是否是根节点,执行挂载完成的回调方法 ### **mounted** **将vodom渲染为真实的dom并且渲染数据。** 只有所有子组件全部挂载完成,才会执行根组件的挂载钩子。 * 完成创建Vm.$el,和双向绑定 * 完成挂载DOM和渲染 * 可进行dom操作 * 可访问$refs * 可发送后端请求,拿回数据 编译、挂载 el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。如果root实例挂载了一个文档内元素,当mounted被调用时,vm.$el也在文档内 数据变化==》beforeUpdate==》虚拟dom重新渲染和patch==》updated ### **数据更改已完成,beforeUpdate(尚未更新dom)** 数据更新时调用,发生在虚拟dom重新渲染和打补丁之前。可以在这一步进一步更改状态,不会触发附加的重渲染过程 * 数据更新之前 * 可在更新前访问现有的dom,如收到移除添加的事件监听器 ![](https://box.kancloud.cn/6454e3f718bb7d90322e0d9e9f4598dc_453x296.png) 在Vue中,数据更改会导致虚拟 DOM 重新渲染,并先后调用beforeUpdate钩子函数和updated钩子函数。 注意:**重渲染(调用这两个钩子函数)的前提是被更改的数据已经被写入模板中**!! ### updated * 完成虚拟dom的重新渲染和打补丁 * 组件dom已更新完成 * 可dom操作 * 不要再次函数中操作数据,会陷入死循环。 组件更新之后 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。(dom已经刷新) ### activated keep-alive包裹的组件在切换时不会进行销毁,而且缓存到内置中 keep-alive组件激活时调用 * 在使用vue-router时有时需要使用<keep-alive>来缓存组件状态,这个时候created构造就不会重复调用了 * 如果我们子组件需要在每次加载的时候进行某些操作,使用activated触发 ### deactivated keeep-alive组件停用时调用 for keep-alive 组件被移除时使用 ### beforeDestroy之后 在实例销毁前调用,此时实例仍然完全可用。此时将组件上的watchers。子组件和事件都移除调。在执行app.$destroy()之前。可做一些删除提示,**可用于销毁定时器,移除事件,解绑全局事件,销毁插件对象** **用于移除事件、定时器等,否则可能会引起内存泄露。** ### destroyed vm.$destroy()被调用,开始卸载组件和监听器,生命周期中级 在Vue实例销毁后调用,调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听会被移除,所有的子组件也会被销毁。这时组件已经没有了。 ### vue数据入口initState开始分析数据驱动更新原理 #### 初始化vue实例 ~~~ Vue.prototype._init = function(options){ initLifycycle(vm); initEvents(vm); initRender(vm); callHook(vm, 'beforeCreate'); initInjections(vm);//resolve injections before data/props initState(vm)//初始化数据的入口 initProvide(vm)//resolve provide after data/props callHook(vm, 'created'); if(vm.$options.el){ vm.$mount(vm.$options.el)//挂载组件 } } //mountComponent是挂载组件时调用的方法 //*hydrating*表示是否直接使用服务端渲染的dom元素, export function mountComponent(vm, el, hydrating){ callHook(vm,'beforeMount'); let updateComponent = ()=>{ vm._update(vm.render(),hydrating) } // true表示 renderWatcher new Watcher(vm, updateComponent,noop,null,true) if(vm.$vnode == null){ vm._isMounted = true; callHook(vm, 'mounted') } } ~~~ #### initState 从数据的入口开始,了解vue是如何使用这几个类完成的数据驱动视图更新的? 初始化state,就是初始化这几个属性。 ![](https://box.kancloud.cn/7b9b34e159b1fa59dc50bdeb820dd7dd_777x65.png) 可观察者对象,具备两个条件 1. 取值的时候,能把要取值的watcher(观察者对象)加入它的dep(依赖,也可叫观察者管理器)管理的subs列表里(即观察者列表) 2. 设置值的时候,有了变化,所有依赖于它的对象(即它的dep里收集到的观察者watcher)都得到通知 #### initProps ![](https://box.kancloud.cn/d8a8043c8f8517d76c9faae5d6c1187f_498x484.png) 循环每个props属性,对每个属性调用defineReactive,把每个属性加上get和set装饰器,变为可观察者对象,如果属性值是对象,也会递归转化。(**对每一个prop,调用proxy函数在Vue对象上建立一个该值的引用(代理到vm实例上)**) #### initMethod(和数据绑定无关) 1. 方法名是否为空 2. 方法名是否和一个prop冲突 3. 方法名是否和已有的Vue实例方法冲突 4. 另外会用**bind将该方法的作用域绑定到Vue实例对象上,且创建一个在Vue实例对象上的引用**。 ~~~ export function bind (fn: Function, ctx: Object): Function { function boundFn (a) { const l: number = arguments.length return l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx) } // record original fn length boundFn._length = fn.length return boundFn ~~~ #### initData ![](https://box.kancloud.cn/16f50268d19468c7549af19286509f05_591x521.png) observe就是循环把data中的所有项都转换成可观察者对象,如果子项是对象或数组就递归转化,确保data里的每一项及其后代都转化成了可观察者对象。 **初始化数据时**,不管data里的数据渲染用没用到,**都会转成可观测者对象**。 对于props和data,**只有哪个watcher用到了取读取时,才会把改watcher加到他的观察者列表中**。 data和props都调用了proxy这个方法, **proxy(vm, '_data',key)**:**proxy就是把data和props下的属性都代理到vm实例下**。vm._data.a等价于vm.a 原理就是Object.defineProperty给vm的key属性设置get和set方法,当访问get的时候,返回的是vm._data[key];,当访问set的时候,设置的是vm._data[key]的值。 #### initComputed ![](https://box.kancloud.cn/5019d1148b6c83bd8441d5a14118f94f_681x647.png) 初始化计算属性,就是为每一个**计算属性定义一个Watcher观察者对象**。这个对象是lazy的,不会立即去执行计算(get方法),等用到的时候才去计算,这时会去读取这个计算属性**依赖的可观察属性的值**来计算,读取时就会把这些依赖添加进这个计算watcher里(deps),同时这些依赖的**订阅者列表**(subs)也会如这个计算watcher。所以当依赖变化时,通知到他的所有订阅watcher。计算watcher接到依赖发生变化了,不会立即计算新值,而是**标记dirty为true**,读取这个计算属性的时候,发现dirty为true,就是说明数据已经不是最新的了,需要重新计算,然后才去计算,否则直接取上一次计算的值value。 如果某个data通过计算属性间接被用到渲染里,那么这个data也会被加入到渲染watcher的**依赖列表**,它的**订阅者列表**页会保存渲染watcher。 只有当模板里使用了该计算属性,这个计算属性依赖的可观察者才会被加入到渲染watcher的列表,**如果模板里没有直接或间接的可观察者对象属性,那么当你set它的时候,也不会触发更新操作。** #### initWatch ![](https://box.kancloud.cn/5019d1148b6c83bd8441d5a14118f94f_681x647.png) 初始化watch,就是为**每个watch属性创建一个观察者对象**,这个expOrFn解析取值表达式去取值,然后就会调用相关data/prop属性的get方法,get方法又会在他的观察者列表里加上改watcher,一旦这些依赖值变化就会通知该watcher执行update方法,即会执行他的回调方法cb,也就是watch属性的handler方法。 到这里数据的初始化就完成了。 #### mountComponent ![](https://box.kancloud.cn/5019d1148b6c83bd8441d5a14118f94f_681x647.png) 这个方法是在,所有的数据初始化完成后,执行挂载组件时调用,**创建一个渲染watcher**,**每个组件有且仅有一个渲染watcher**,updateComponent是watcher的getter属性,**创建后,立即调用get方法,即调用updateComponent,也就是调用render方法**,render里使用了数据就会读取相关的data的get方法,**就会把data的依赖加进这个渲染watcher的依赖列表(deps)里**,data的**subs**也会加入渲染watcher,如此,当设置**data是拦截set方法就会通知渲染watcher调用update方法**。 #### 总结 一个数据变更后,通知他的Watcher(观察者)去执行update 不同类型的Watcher职责不同,vue里的Watcher可以分为3类: * 渲染Watcher的update,**赋值重新渲染**,执行render,getter是updateComponent * 计算Watcher的update,**负责标记dirty,告诉它数据不是最新的需要重新计算了**,getter是计算属性的get方法。 * 侦听器Watcher的update,**赋值执行回调方法**,也就是watch的handler;getter是**watch的取值表达式**。 ### vue基础学习 ~~~ var vm = new Vue({ el:'选择器',//挂载到页面的那个元素里,即确定vue的作用范围,外部可通过vm.$el访问,得到的是一个元素dom元素,可进行操作。 a: '',//自定义属性,外部可通过vm.$options访问 data:{},//实例属性都在这里,外部通过实例名,即vm.$data调用 computed:{},//计算属性,也是实例属性,只是以方法的形式存在,并可以有逻辑运算的属性 method:{},//实例方法都在这 watch:{},//对data和computed的属性进行监听,当属性有变化时自动触发,已方法的形式存在,外部通过$.watch调用 //注意,以上属性和方法,实例内部都通过this调用,外部则通过对应的实例方法访问 //在vue的生命周期中,他还提供了一系列的钩子函数,进行自定义逻辑的注入 ~~~ created: function(){ 实例已经创建 }   beforeCompile: function(){ 模块编译之前 }   compiled: function(){ 模块编译之后;即模板占位符被是内容替换}   ready: function(){ 模板插入到文档中了;相当于window.onload }   注意: 以上4个方法在对象被实例化后即按顺序执行,以下2个方法需通过事件触发,并通过调用 实例名.$destory() 才执行   beforeDestroy: function(){ 对象销毁之前 }   destroyed: function(){ 对象销毁之后 } }) ~~~ **el**:挂载到页面的那个元素里,即确定vue的作用范围,外部可通过vm.$el访问,得到的是一个元素dom元素,可进行操作。 **a**: 自定义属性,外部可通过vm.$options访问 watch:{},//对data和computed的属性进行监听,当属性有变化时自动触发,已方法的形式存在,外部通过$.watch调用 1. vue对象属性:data,el,options,watch,computed 2. 对象方法:声明周期值钩子函数 3. 对象实例访问和调用属性和方法 $options,$el,$data,$watch 浅度监听 ~~~ vm.$watch("监听的实例属性名",function() { // 对于监听数据变化后的业务处理代码 }); --浅度监听 ~~~ 深度监听 ~~~ vm.$watch("监听的实例属性名",function() { // 对于监听数据变化后的业务处理代码 },{deep: true});  --深度监听 ~~~ 浅度监听可监听基本数据类型,如果监听的属性是对象,需要进行深度监听,对象内部的数据有变化是可以监听到的。 4. 自带过滤器 自定义过滤器 capitalize(首字母大写)、uppercase、currency、json( 相当于JSON.Stringify() )、debounce(后跟秒数,配合事件,延迟执行) limitBy(参数1, 参数2) 常用语v-for数组,限制输出数量和从哪输出;参数1代表输出几个,参数2代表从第几个输出过滤,打到热搜索的效果 orderBy(参数)  对数据排序,参数为1时为正序,为-1时则倒序,其他什么参数呢?所以1和-1基本是常用情况** 5. 自带指令和自定义指令 A:自带指令:v-if、v-show、v-else、v-module、v-text、v-html、v-bind、v-on、v-el、v-cloak... {{实例属性}},网速比较慢是,页面出现闪烁的时候会把花括号和里面的原生内容显示出来,用户体验不好 * 在较大段落元素上使用v-clock指令,并设置该元素的css:display:none; * 使用v-text/v-htm; B: 自定义指令 ~~~  Vue.directive("指令名称",function(..){     this.el.style.background = 'red'; //这里的this代表new出来的实例,this.el代表原生的dom元素   }); ~~~ 模板中使用v-指令名称进行使用,或v-指令名称="参数",可以在调用指令是进行传参 定义指令名称时不加v-,模板使用时加v- ### initEvents ~~~ export function initEvents(vm: Component){ vm._events = Object.create(null); vm._hasHookEvent = false; //init parent attached events const listeners = vm.$options._parentListeners; if(listeners){ updateComponentListeners(vm, listeners); } } ~~~ vm._events该属性笼统的来说就是存放事件的对象。其实vm.events表示的是**父组件绑定在当前组件上的事件**。 **vue.$on:监听当前实例上的自定义事件。**事件可以有vm.$emit触发,回调函数会接收所有传入事件触发函数的额外参数。(这种方法类似dom中的addEventListener事件和dispatchEvent触发事件)。**vue.$on主要就是把传入的方法push到_events属性里,方法之后被$emit调用。** vm.$once:监听一个自定义事件,但是只触发一次,在第一次触发之后移除监听器。 on和once最本质的区别:**触发once绑定的回调的时候,执行on方法,先调用$off方法移除监听,然后在执行回调函数。(只触发一次)** vm.$off ### new Vue()都干了什么? vm.$options:获取自定义属性(methods,directives以及components...将相关的属性和方法都放到vm.$options中**,两个来源:一个是Vue的构造函数(parent)一个是new Vue传入的child,最终生成统一的options**) **option是一个对象,可以选择如下选项:data函数成员、methods对象成员、模板template、挂载元素el、生命周期钩子、props属性声明、computed计算成员、watch监视成员等。** ~~~ //合并options(父子组件) Vue.prototype._init = function (options?: Object) { if (options && options._isComponent) { initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } initProxy(vm) //代理vm属性 vm._self = vm initLifecycle(vm) // 初始化一些和生命周期相关的内容 initEvents(vm) // 初始化事件相关属性,当有父组件的方法绑定在子组件时候,供子组件调用 initRender(vm) // 添加slot属性 callHook(vm, 'beforeCreate') // 调用beforeCreate钩子 initInjections(vm) // resolve injections before data/props initState(vm) // 初始化数据,进行双向绑定 state/props initProvide(vm) // resolve provide after data/props 注入provider的值到子组件中 callHook(vm, 'created') // 调用created钩子 if (vm.$options.el) { // 把模板转换成render函数 vm.$mount(vm.$options.el) } ~~~ initProxy ~~~ initProxy = function initProxy(vm){ if(hasProxy){ const options = vm.$options; const handles= options.render && options.render._withStripped ?getHandler:hasHandler vm._renderProxy = new Proxy(vm, handlers); }else{ vm._renderProxy = vm; } } ~~~ 代理对象是es6的新特性,它主要用来自定义对象一些基本操作(如查找,赋值,枚举等)。 #### 分部分析 第一部分:设置属性,uid以及isVue的flag 第二部分:对options进行合并,vue会将相关的属性和方法都统一放到vm.$options中,为后续的调用做准备工作。vm.$option的属性来自两个方面,一个是vue的构造函数(vm.constructor)预先定义的,一个是new Vue时传入的参数对象。 ~~~ var vm = new Vue({ el:"#app", data:{ msg:'tttt' } }) ~~~ 为例 ![](https://box.kancloud.cn/a57e65babbb3f14b3fce03a8648a046e_459x192.png) 第三部分:初始化各类属性和事件 ![](https://box.kancloud.cn/0a639d48a20d68ac4aebc5e9784b9eb5_1020x555.png) **initProxy:设置vm._renderProxy(为我们vm属性添加一些自定义的行为) initLifycycle:初始化一系列变量,初始化一些生命周期相关的属性,以及parent,child等属性赋值($parent:父实例,$root:根vue实例,$children:直接子组件,$refs:一个对象,已注册过ref的所有子组件,`_watcher`:组件实例响应的watcher实例对象,_inactive...) initEvents:存储父组件绑定当前子组件的事件,保存到vm._events. initRender:定义vm._c和vm.$createElement等方法 callHook:调用声明周期的钩子相关方法,包括beforeCreate,created initInjections和initProvide:通过逐级查找,从父级provide中获取子级组件inject定义的属性值,并增加对该属性的监听。 initState:是对prop,method,data,computed,watch的初始化,增加对定义属性的监听。** 第四部分:挂载。前几部分是准备阶段,这部分是new Vue的核心部分,将template编译成render表达式,然后转为Vnode,最终渲染为真实的dom节点。 ![](https://box.kancloud.cn/a57e65babbb3f14b3fce03a8648a046e_459x192.png) #### 挂载 从挂载开始,就进入了正式的渲染工作,直到页面呈现出来。思考应该做哪些工作 1. 将template中的各变量,表达式替换成实际的值。替换后形成实际的dom,并渲染出来 2. 建立一种更新机制,当数据更新后,dom也重新渲染。 ![](https://box.kancloud.cn/0e49f267188a2b950a627ed49e2d8db1_906x293.png) * html字符串提取,无论是el还是template,最后都是提取html的字符串 * 编译,将html的字符串编译成AST抽象树,在拼接成render表达式 * 形成真是的dom,render转为vnode,最终生成时间的dom,并增加更新的监听 从源码分析 ##### 编译时的$mount Vue中$mount出现在两个文件中,前一个文件,会将普通的**template字符串转换成render语法**,然后**调用后一个文件中的mount,完成dom的呈现**。 1. 根据el或者template,获取到html的字符串 2. 将字符串转成render函数表达式(这个过程涉及到编译) 3. 调用runtime/index.js中的mount定义,继续后面的流程。 ##### 运行时的mount 运行时的mount负责真正的挂载过程,将render表达式转化成vnode,最终创建真是的dom节点。 完整的挂载过程: 1. 执行beforeMount回调方法 2. 定义updateComponent放,vm._render,实现将render表达式转为vnode,vm._update将vnode渲染成实际的dom 3. 构建watcher实例,两个作用 * 执行updateComponent方法,实现dom的渲染,并完成**表达式对属性变量的依赖收集**。 * 一旦包含的表达式中的属性变量有变化,将重新执行update。 4. 判断是否是根节点,执行挂载完成的回调方法 ##### vm._render 该方法将render表达式转为vnode,vnode是一系列dom属性的集合,可以认为是简化了的dom。调用的是vm._c创建各级的vnode ##### vm._update vm._update会把vnode渲染成真是的dom节点,调用事件有两个地方 **第一个是首次渲染,第二个是数据更新。** 调用`vm.__patch__`进行首次渲染。`vm.__patch__(vm.$el, vnode, hydrating, false )` vm.$el是id为app的dom,vnode是render后的虚拟对象,hydrating表示是否是服务端渲染。 最终是调用原生的方法**documnt.createElement,setAttribute,appendChild**实现了dom节点的创建。 ![](https://box.kancloud.cn/5945bbcc6e34394afb73dc617ee732fd_918x441.png) ##### initLifycycle :初始化一系列变量,初始化一些生命周期相关的属性,以及parent,child等属性赋值$parent:父实例 $root:根vue实例,没有将指向自己 $children:当前实例的直接子组件 $refs:一个对象,已注册过ref的所有子组件 `_watcher`:组件实例相应的watcher实例对象 _inactive:keep-alive中组件状态,如被激活,该值为false,反之为true _directInactive:也表示keep-alive中组件状态的属性。 _isMounted:当前实例是否完成挂载(mounted) _isDestroyed:当前实例是否已经被销毁(destroyed) _isBeingDestroyed ![](https://box.kancloud.cn/136fb5d4a281ae5f7c8bb2097d8edfd7_581x78.png) ##### provide inject provide选项应该是一个对象或返回一个对象的函数。**该对象包含可注入其子孙的属性**。 inject选项应该是一个字符串数组或一个对象,该对象的key代表了本地绑定的名称,value为其key已在可用的注入中搜索。