vue的生命周期
beforeCreate(创建前) -> created(创建后) -> berforeMount(载入前) -> mounted(载入后) -> beforeUpdate(更新前) -> updated(更新后) -> beforeDestory(销毁前) -> destoryed(销毁后)
完整的Vue
new Vue({
el: "",
data: {
},
computed: {
//computed是计算属性,也就是依赖其它的属性计算所得出最后的值
//1、computed内部的函数在调用时不加()。
//2、computed是依赖vm中data的属性变化而变化的,也就是说,当data中的属性发生改变的时候,当前函数才会执行,data中的属性没有改变的时候,当前函数不会执行。
//3、computed中的函数必须用return返回。
//4、在computed中不要对data中的属性进行赋值操作。如果对data中的属性进行赋值操作了,就是data中的属性发生改变,从而触发computed中的函数,形成死循环了。
//5、当computed中的函数所依赖的属性没有发生改变,那么调用当前函数的时候会从缓存中读取。
},
watch: {
//watch是去监听一个值的变化,然后执行相对应的函数。
//1、watch中的函数名称必须要和data中的属性名一致,因为watch是依赖data中的属性,当data中的属性发生改变的时候,watch中的函数就会执行
//2、watch中的函数有两个参数,前者是newVal,后者是oldVal。
//3、watch中的函数是不需要调用的。
//4、watch只会监听数据的值是否发生改变,而不会去监听数据的地址是否发生改变。也就是说,watch想要监听引用类型数据的变化,需要进行深度监听。"obj.name"(){}------如果obj的属性太多,这种方法的效率很低,obj:{handler(newVal){},deep:true}------用handler+deep的方式进行深度监听。
//5、特殊情况下,watch无法监听到数组的变化,特殊情况就是说更改数组中的数据时,数组已经更改,但是视图没有更新。更改数组必须要用splice()或者$set。this.arr.splice(0,1,100)-----修改arr中第0项开始的1个数据为100,this.$set(this.arr,0,100)-----修改arr第0项值为100。
//6、immediate:true 页面首次加载的时候做一次监听。
},
components: {
//组件通信 用于父组件内 引用组件
},
props: {
//组件通信 用于子组件内 接收父组件传递给子组件的数据
},
methods: {
//事件方法执行
},
created() {
//html加载完成之前,执行。执行顺序:父组件-子组件
},
mounted() {
//html加载完成后执行。执行顺序:子组件-父组件
}
});
computed与watch的区别:
1、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
2、是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
3、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
4、使用场景:computed----当一个属性受多个属性影响的时候,使用computed-------购物车商品结算。watch----当一条数据影响多条数据的时候,使用watch-------搜索框。
Vue执行流程
beforeCreate调用
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
在这个钩子函数里,只是刚开始初始化实例,你拿不到实例里的任何东西,比如data和methods和事件监听等。
data: {
msg: 'linlin'
},
methods: {
getLists(){
return 'aaa'
}
},
beforeCreate() {
console.log('beforeCreate',this.msg,this.getLists())
}
执行结果报错
new Vue
从 new Vue开始作为入口,Vue只是一个简单的构造函数
function Vue (options) {
this._init(options)
}
进入_init函数后,先初始化了一些属性,然后开始第一个生命周期
callHook(vm, 'beforeCreate')
至此beforeCreate被调用完成
beforeCreate之后开始进行初始化
==========================================
created调用
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前尚不可用。
这是最早能拿到实例里面的数据和方法的一个钩子函数。应用场景:异步数据的获取和对实例数据的初始化操作都在这里面进行。
data: {
msg: 'linlin',
imgs: null
},
methods: {
getLists(){
this.$http.get(url).then(res=>{
this.imgs = res.data.lists
console.log(this.imgs)
})
}
},
created() {
this.getLists()
}
=================================
beforeMount调用
在挂载开始之前被调用:相关的render函数首次被调用。
<div id="app">
<ul>
<li v-for="(item,index) in itemList" :key="index">{{item}}</li>
</ul>
</div>
<script>
let app = new Vue({
data: {
itemList: [1,2,3]
},
created() {
console.log('created',document.querySelectorAll('li').length)
},
beforeMount() {
console.log('beforeMount',document.querySelectorAll('li').length)
},
mounted() {
console.log('mounted',document.querySelectorAll('li').length)
},
})
</script>
不论是created还是beforeMount在它们里面都拿不到真实的dom元素,如果我们需要拿到dom元素就需要在mounted里操作
======================
Mounted调用
mounted可以拿到dom元素,但也只是能拿到初始化数据里的dom元素,如果是存在异步对dom元素数据进行更改我们就只能在updated里获取,应用场景:初始数据(在data中有的)的dom渲染完毕,可以获取dom
另外$children子组件的获取也需要在mounted里
<div id="app">
<ul>
<li v-for="(item,index) in itemList" :key="index">{{item}}</li>
</ul>
</div>
<script>
let app = new Vue({
data: {
itemList: [1,2,3]
},
created() {
setTimeout(()=>{
this.arr = [4,5,6,7];
console.log('created',document.querySelectorAll('li').length)
})
},
mounted() {
console.log('mounted',document.querySelectorAll('li').length)
},
beforeUpdate(){
console.log('updated',document.querySelectorAll('li').length)
},
updated(){
console.log('updated',document.querySelectorAll('li').length)
}
})
</script>
==========================
beforeUpdate
当数据更新后出发的钩子函数,这个钩子函数里拿到的是更改之前的数据,虚拟DOM重新渲染和打补丁之前被调用。
你可以在这个钩子中进一步地修改data,这不会触发附加的重渲染过程。
==========================
updated
上面虽然能在update里拿到更改后的数据,但是并不建议在这里面进行对异步数据得到的dom操作,因为有可能你当前的数据不止更改一次,而update只要相关的数据更改一次就会执行一次,**注意:updated是指mouted钩子后(包括mounted)的数据更改,在created里的数据更改不叫更改叫做初始化,**所以我们下面在created里修改数据是通过一个异步来确保updated可以执行的。我们一般都是在事件方法里更改数据,然后通过updated对其操作。应用场景:如果dom操作依赖的数据是在异步操作中获取,并且只有一次数据的更改 ,也可以说是数据更新完毕:如果对数据更新做一些统一处理在updated钩子中处理即可。
注意:当这个钩子被调用时,组件DOM的data已经更新,所以你现在可以执行依赖于DOM的操作。但是不要在当前钩子(updated)里修改当前组件中的data,否则会继续触发beforeUpdate、updated这两个生命周期,进入死循环!
created() {
setTimeout(()=>{
this.arr = [4,5,6,7]
console.log('created',document.querySelectorAll('li').length)
})
setTimeout(()=>{
this.arr = [10,11,12,13,14]
console.log('created',document.querySelectorAll('li').length)
},1000)
},
beforeUpdate() {
console.log('beforeUpdate',document.querySelectorAll('li').length)
},
updated() {
console.log('updated',document.querySelectorAll('li').length)
},
数据每更改一次 都会执行beforeUpdate updated
在事件方法里更改数据也会触发updated
<div id="app">
<ul>
<li v-for="(item,index) in arr" :key="index" @click="getAdd">{{item}}</li>
</ul>
<div>{{msg}}</div>
</div>
data: {
arr: [1,2,3],
},
methods: {
getAdd(){
this.arr = [4,5,6,7]
}
},
updated() {
console.log(this.arr)
}
如果想分别区别不同的数据更新,同时要对dom进行操作那么需要使用nextTick函数处理
nextTick(),是将回调函数延迟在下一次dom更新数据后调用
简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数
created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
created() {
setTimeout(()=>{
this.arr = [4,5,6,7]
this.$nextTick(()=>{
console.log('nextTick',document.querySelectorAll('li').length)
})
})
setTimeout(()=>{
this.arr = [10,11,12,13,14]
this.$nextTick(()=>{
console.log('nextTick',document.querySelectorAll('li').length)
})
},1000)
},
**在created内执行nextTick nextTick在updated后执行 **
updated,watch和nextTick区别
updated对所有数据的变化进行统一处理
watch对具体某个数据变化做统一处理
nextTick是对某个数据的某一次变化进行处理
如果实例里面没写el挂载点你就需要在实例后面通过.$mount(’#app’)来手动触发
======================
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用
=======================
destroyed
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
beforeDestroy和destroyed只能通过手动触发$destroy来调用
let app = new Vue({
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
}
})
app.$destroy()
Vue 的父组件和子组件生命周期钩子执行顺序是什么
- 1.加载渲染过程:
- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 父组件挂载完毕肯定是等里面的子组件都挂载完毕后才算父组件挂载完毕了,所以父组件的mounted在最后。
- 2.子组件更新过程:(子组件更新影响父组件的情况)
- 父beforeUpdate->子beforeUpdate->子updated->父updated
- 3.子组件更新过程:(子组件更新不影响父组件的情况)
- 子beforeUpdate->子updated
- 4.父组件更新过程:(父组件更新影响子组件的情况)
- 父beforeUpdate->子beforeUpdate->子updated->父updated
- 5.父组件更新过程:(父组件更新不影响子组件的情况)
- 父beforeUpdate->父updated
- 6.销毁过程:
- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed