## 生命周期钩子函数
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已在可用的注入中搜索。
- 空白目录
- 双樾
- JS基础知识
- JS-WEB-API
- 开发环境
- 运行环境
- ES6
- 原型
- 异步
- 虚拟dom
- mvvm
- 组件化和React
- hybrid
- 其他
- 补充
- 技巧
- 快乐动起来呀
- css
- 掘金小册子
- js基础知识
- ES6知识点
- JS异步
- JS进阶知识
- 思考题
- DevTools Tips
- 浏览器基础知识
- 浏览器缓存机制0
- 浏览器渲染原理
- 安全防范知识点0
- 从V8中看JS性能优化0
- 性能优化琐碎事
- Webpack性能优化0
- 实现小型打包工具0
- React和Vue
- Vue生命周期
- vue基础知识点
- Vue响应式
- vue高级
- React基础
- Vue.js技术解密
- 准备工作
- 数据驱动
- new Vue()
- vue实例挂载
- 组件化
- 深入响应式原理
- 编译
- 扩展
- Vue Router
- Vuex