随着对 vue 的不断了解,会越来越发现它生命周期的重要性,只有了解了它的生命周期,才能在开发项目的时候在逻辑上的很好的判断什么时候该发生什么事件,即很好的控制页面。

一、什么是 vue 生命周期

Vue 的生命周期钩子函数是 Vue 实例在不同生命周期阶段会自动调用的一些函数。 

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。下面是官网中的生命周期照片

二、生命周期函数

Vue 的生命周期主要共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后;还有keep-alive 缓存特殊的两个阶段(activated(组件激活时)、deactivated(组件停用时));每次进入都会执行钩子中的函数。

1、beforeCreate(创建前)

表示实例完全被创建出来之前,vue 实例的$el 未存在和数据对象 data 都为 undefined,还未初始化,不能使用。此钩子函数不能获取到数据,dom元素也没有渲染出来,此钩子函数不会用来做什么事情。
beforeCreate中可以获取到this,但是此时实例未初始化只能获取到this对象内以$开头的键值,若访问data中的属性时,会返回 undefind

2、created(创建后)

这里实例创建完成之后,在这里完成了数据监测,数据对象 data 已存在,可以调用 methods 中的方法,操作 data 中的数据  不会触发updated  不会触发视图,但 dom 未生成,$el 未存在 。在这个钩子函数里面,如果同步更改数据的话,不会影响运行中钩子函数的执行。可以用来发送ajax请求,也可以做一些初始化事件的相关操作。

此阶段若要操作dom,需要在外面包裹一层 $nextTict(() => {}) 用于在DOM更新完成后执行回调函数的方法 

3、beforeMount(挂载前)

完成了模板编译,虚拟DOM 已经完成创建,即将渲染;修改数据,不会触发updated。vue 实例的 $el 和 data 都已初始化,dom节点马上要被渲染出来了,但是还没有真正的渲染出来,挂载之前为虚拟的 dom节点,模板已经在内存中编辑完成了,但是尚未把模板渲染到页面中。data.message 未替换。

4、mounted(挂载后)

vue 实例挂载完成,data.message 成功渲染。内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了。实例创建期间的最后一个生命周期函数仅仅执行一次,当执行完 mounted 就表示,实例已经被完全创建好了,DOM 渲染在 mounted 中就已经完成了。最早操作dom的时机

keep-alive 缓存特殊的两个阶段:

5、activated(组件激活时)            该钩子在服务器端渲染期间不被调用。

被 keep-alive 缓存的组件激活时调用。初始化操作放在actived里面

6、deactivated(组件停用时)        该钩子在服务器端渲染期间不被调用。

被 keep-alive 缓存的组件停用时调用。在deactived里面,在里面进行一些善后操作

添加keep-alive标签后会增加activated和deactivated这两个生命周期函数,初始化操作放在actived里面,一旦切换组件,因为组件没有被销毁,所以它不会执行销毁阶段的钩子函数,所以移除操作需要放在deactived里面,在里面进行一些善后操作,这个时候created钩子函数只会执行一次,销毁的钩子函数一直没有执行。

设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activateddeactivated):

  • 首次进入组件时:beforeRouteEnter > beforeCreate > createdmounted > activated > ... ... > beforeRouteLeave > deactivated
  • 再次进入组件时:beforeRouteEnter >activated > ... ... > beforeRouteLeave > deactivated

keep-alive的时页面刷新时触发3个钩子函数 activated,beforeUpdate,updated,切换,前进,后退触发activated,deactivated 

从上可以看出:第一次加载页面会触发哪几个钩子函数? 

  • 四个钩子
    • beforeCreate,
    • created,
    • beforeMount,
    • mounted 

举个栗子:

当我们从首页–>列表页–>商详页–>再返回,这时候列表页应该是需要keep-alive

首页–>列表页–>商详页–>返回到列表页(需要缓存)–>返回到首页(需要缓存)–>再次进入列表页(不需要缓存),这时候可以按需来控制页面的keep-alive

在路由中设置keepAlive属性判断是否需要缓存 

{
    path: 'list',
    name: 'itemList', // 列表页
    component (resolve) {
    require(['@/pages/item/list'], resolve)
},
    meta: {
        keepAlive: true,
        title: '列表页'
    }
}

 使用<keep-alive>

<div id="app" class='wrapper'>
    <keep-alive>
    <!-- 需要缓存的视图组件 -->
    <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
keep-alive缓存后如何获取数据?

解决方案可以有以下两种:

// 方案一(推荐)
beforeRouteEnter(to, from, next){
    next(vm=>{
        console.log(vm)
        // 每次进入路由执行
        vm.getData()  // 获取数据
    })
},

// 方案二
activated(){
    this.getData() // 获取数据
},
// 注意:服务器端渲染期间avtived不被调用

7、beforeUpdate(更新前)

组件数据更新之前使用,data数据是新的,页面上的数据是旧的,组件即将更新,准备渲染,可以改数据。运行中钩子函数beforeUpdate默认是不会执行的,当数据更改的时候,才会执行。数据更新的时候,先调用beforeUpdate,然后数据更新引发视图渲染完成之后,再会执行updated。运行时beforeUpdate这个钩子函数获取的数据还是更新之前的数据(获取的是更新前的dom内容),在这个钩子函数里面,千万不能对数据进行更改,会造成死循环。data 数据尚未和最新的数据保持同步。

8、updated(更新后)

render重新做了渲染,这时数据和页面都是新的。这个钩子函数获取的数据是更新后的数据,生成新的虚拟dom,跟上一次的虚拟dom结构进行比较,比较出来差异(diff算法)后再渲染真实dom,当数据引发dom重新渲染的时候,在updated钩子函数里面就可以获取最新的真实dom了。页面和 data 数据已经保持同步了。

9、beforeDestory(销毁前)

切换路由的时候,组件就会被销毁了,销毁之前执行beforeDestroy。在这个钩子函数里面,我们可以做一些善后的操作,例如可以清空一下全局的定时器(created钩子函数绑定的初始化阶段的事件)、清除事件绑定。

Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁

10、destoryed(销毁后)

组件销毁后执行destroyed,销毁后组件的双向数据绑定、事件监听watcher相关的都被移除掉了,对 data 的改变不会再触发周期函数但是组件的真实dom结构还是存在在页面中的。

这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

刷新页面vue做了什么?

使用浏览器直接刷新网页不会触发vue生命周期里beforeDestory destoryed 这两个函数的。因为浏览器直接刷新页面就相当于再次访问一遍这个网址可以理解为是浏览器的主动行为。但会触发created、mounted。

如果想监听页面的刷新的或者浏览器的刷新操作,可以在mounted 里面用这个方法:

export default {
  mounted() {
    window.addEventListener('beforeunload', this.handleBeforeUnload);
  },
  methods: {
    handleBeforeUnload(event) {
      // 在这里可以执行你想要的操作
      // 如果你想要阻止刷新,可以设置 event.returnValue
      // 这将显示浏览器的标准警告信息
      // event.returnValue = '你确定要离开此页面吗?';
    }
  },
  beforeDestroy() {
    // 一定要在组件销毁前移除事件监听,避免内存泄露
    window.removeEventListener('beforeunload', this.handleBeforeUnload);
  }
};

1. 刷新页面时,Vue会重新执行初始化过程

当页面刷新时,Vue会重新执行初始化过程。这包括重新加载Vue实例、组件以及其他相关的Vue插件。Vue会通过重新渲染DOM来确保页面的显示与数据的同步。如果你在Vue实例的生命周期钩子函数中有相关的操作,例如created或mounted,这些钩子函数会再次被调用。

2. 刷新页面会导致Vue实例的数据重置

刷新页面会导致Vue实例的数据重置。Vue的响应式系统会在页面刷新时重新初始化,将data属性中的数据恢复到初始状态。这意味着如果你在页面刷新前对Vue实例的数据进行了修改,刷新后这些修改将被丢失。因此,在刷新页面前,你可以考虑使用Vue提供的持久化数据的方法,例如使用本地存储或后端存储来保存数据。

3. 刷新页面会触发Vue路由的导航守卫

如果你在Vue项目中使用了Vue Router进行路由管理,刷新页面会触发Vue路由的导航守卫。导航守卫是一组路由钩子函数,可以在路由切换前、后以及错误时执行一些操作。当页面刷新时,Vue会根据当前URL重新匹配路由,并执行相应的导航守卫。这可以让你在页面刷新时执行一些特定的操作,例如重新获取用户身份验证信息或清除缓存数据。

简述每个周期具体适合哪些场景

beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框、清除定时器
nextTick : 更新数据后立即操作dom

补充知识点:

1.vue请求数据放在created好还是mounted里好?

建议放在created里
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,这是dom已经挂载完成,可对html的dom节点进行一些需要的操作。

如果在mounted钩子函数中请求数据可能导致页面闪屏问题
其实就是加载时机问题,放在created里会比mounted触发早一点,如果在页面挂载完之前请求完成的话就不会看到闪屏了。

请求的数据对DOM有影响,那么使用created;如果请求的数据对DOM无影响,可以放在mounted。 

2.请你说说vue中$nextTick(() => {})用法及原理

2.1. 定义

在下次 DOM 更新循环结束之后执行延迟回调(异步)。在修改数据之后立即使用这个方法,获取更新后的 DOM。 

事件循环 中宏任务和微任务这两个概念

  • nextTick 的原理是 vue 通过异步队列控制 DOM 更新
  • nextTick底层是 promise,所以是微任务。

其实vue在版本更新的时候。 时而将nextTick封装成宏任务,时而将nextTick封装成微任务。 不过目前vue2最新的版本,nextTick底层是微任务

官方理解:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

个人理解:nextTick(),是将回调函数延迟在下一次dom更新数据后调用,即数据更新了,在dom渲染完成后调用该函数

2.2. 应用场景

    2.2.1在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中

    2.3.2在created()钩子函数执行的时候DOM 其实并未进行任何渲染

    在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。

3.nextTick和setTimeout区别

首先Vue 在更新 DOM 时是异步执行的,也就是说数据变了,DOM不会立即改变,那么我们是如何知道DOM什么时候会改变呢?也就是说如何知道异步后的触发时机呢?

可以通过nextTick方法,这个方法在源码内,先监听是否具备Promise.then,利用promise来监听,如果当前环境不支持promise,那么就优雅降级采用MutationObserver,如果MutationObserver不支持的话,那么就降级采用setImmediate,如果setImmediate不支持的话,那么就使用setTimeout(fn, 0)。

所以说nextTick和setTimeout区别总结就是:优雅降级->nextTick会先尝试使用promise.then、MutationObserver、setImmediate这些技术去监听,如果都不支持才会采用setTimeout

父子组件的执行顺序:

  • 加载渲染过程

父beforeCreate->父created->父beforeMount->

子beforeCreate->子created->子beforeMount->子mounted->父mounted

父组件挂载到vue实例之上时,要确保子组件已经挂载到父组件上 

  • 子组件更新过程

父beforeUpdate->子beforeUpdate->子updated->父updated

  • 父组件更新过程

父beforeUpdate->父updated

  • 销毁过程  - 销毁父组件时,先将子组件销毁后才会销毁父组件 ;

 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

兄弟组件的执行顺序:

1.如果有兄弟组件,父组件开始执行到beforeMount,然后兄弟组件依次执行到 beforeMount,然后按照顺序执行mounted,最后执行父组件的mounted;

2.兄弟组件的初始化(mounted之前)是分开进行,挂载是从上到下依次进行 ~当没有数据关联时,兄弟组件之间的更新和销毁是互不关联的。

三、小结

created:html加载完成之前执行。执行顺序:父组件-子组件
mounted:html加载完成后执行。执行顺序:子组件-父组件
methods:事件方法执行
watch:watch是去监听一个值的变化,然后执行相对应的函数,默认无数据改动不执行  需要配置{immediate:true}初始化会执行一次
computed:computed是计算属性,也就是依赖其它的属性计算所得出最后的值,默认初始化是执行一次的

computed、watch 区别

created():dom还未生成,仅仅触发一次;
mounted:dom渲染完毕,仅仅执行一次;
activated():在使用时keep-live主要目的是可以使用缓存,避免组件重新渲染;只要进入组件激活就会触发。

在 Vue 2 中,这些选项的执行顺序是:

1. props :父组件传递给子组件的属性会首先被处理。
2. data :在处理完 props 之后,Vue 会处理数据对象中的所有属性,并将它们添加到 Vue 实例中。
3. created :在处理完所有选项后,Vue 实例会调用 created 钩子,并完成实例化。
4. beforeMount
5. computed :在HTML DOM加载后马上执行的,如赋值;计算属性会在处理完 data 之后被计算,并添加到 Vue 实例中。
6. mounted :在实例挂载到DOM元素之后,Vue 实例会调用 mounted 钩子。
8. watch :侦听器会在 computed 之后被处理,并添加到 Vue 实例中。
9. methods :必须要有一定的触发条件才能执行,如点击事件;实例方法会在 mounted 之后被处理,并添加到 Vue 实例中。

computed 是在HTML DOM加载后马上执行的 即在beforeMount后mounted前触发。 

如果watch添加 immediate:true 属性(在beforeCreate后created前执行),则先执行watch、再执行computed。

综上,默认选项的执行顺序是 props -> data -> created -> beforeMount -> computed -> mounted -> watch -> methods。

注意:等触发某一事件后,则是:先methods再watch。

immediate:true   props -> data ->  watch -> created -> beforeMount -> computed -> mounted -> methods。

SPA应用

SPA,全称为Single Page Application(单页应用程序),仅在该Web页面初始化时加载相应的HTML、JavaScript、CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载 ,而是动态地根据用户的操作更新页面的部分内容。这种模式提供了更加流畅和快速的用户体验,因为它减少了页面加载的次数和服务器的请求。

SSR

SSR,全称为Server-Side Rendering 也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端

SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreatecreated两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器会有更大的负载需求。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐