面试官:聊下vue的生命周期

1,486 阅读7分钟

当我们跳转页面的时候,需要在页面加载中发请求,拿到数据。请求函数可以写在上一个页面的点击事件,但是一般不会这样写,因为数据量太大了,数据放在浏览器地址栏不够放,所以就是来到这个页面去发请求,我们一般都是放在当前页面的生命周期中发请求

vue的生命周期有如下这些

1.png

其中

这四个钩子函数你基本上很少用上,一般都是用于调试。error和两个render都是捕获错误的,server是作服务端渲染的。

今天来认识下这些钩子函数

钩子函数就是生命周期函数,所谓生命周期就是让函数在页面加载的过程中自动执行,语法都是接受一个回调

vue的代码先会被去读到,然后进行编译,template代码浏览器是读不懂的,因此需要先进行编译,编译完就开行进行挂载,当vue代码片段被拿去挂载mount,生命周期就会执行

挂载是main.js的职责,挂载就是把指定的template的代码放到index.html中去渲染

onBeforeMount()

onBeforeMount翻译过来就是挂载之前,也就是说此时的vue代码已经被编译完毕了

onMounted()

onMounted就是挂载之后

我们不妨看看下面的打印顺序

<script setup>
import { onMounted, onBeforeMount} from 'vue';

console.log('hello') 

onMounted(() => {
	console.log('onMounted'
}

onBeforeMount(() => {
	console.log('onBeforeMount')
}
</script>

2.png

console.log放在全局中执行,这个执行是在编译之后执行的,vue生命周期的template需要先编译再挂载,整个过程是比全局慢一步的,因此和钩子函数相比,全局函数是优先执行的

这里故意将onBeforeMount放在onMounted函数后面,就是为了证明onBeforeMount一定是优先于onMounted的执行,无论代码位置

我们再来试试看在这三个打印中分别附上一个dom结构的打印

3.png

4.png

在全局中没有获得这个dom结构,如何理解:拿到dom结构指的是浏览器,在执行这个代码的时候,页面还没有挂载,是拿不到dom结构的,所以这个打印如果你放在onBeforeMount也是无法打印的,只有onMounted才可以拿到。

问题来了,从后端发请求的代码应该放在这三个中的哪一个

其实三个都可以,但是我们习惯性的会放在onMounted中,因为有些数据拿到之后可能会操作dom结构

onUnmounted()

onUnmounted是卸载的意思,所以这个钩子就是在页面卸载的时候执行,其实就是离开页面的时候。

这个钩子函数的用处不多,不过当我们如果想要掐灭当前页面的定时器的时候可以用这个钩子,因为有时候离开当前页面的时候定时器还会存在,影响性能。

onUpdated()

onBeforeUpdate()

这两个钩子都是在数据源更新的时候使用,只要响应式数据发生变更,就会触发这个钩子的执行,有点类似watch监听器

接下来聊聊路由里面的钩子函数,这才是今天的主角。其实就是围绕着下面这些来讲,路由官网的进阶教程

5.png

路由的钩子函数

路由的钩子函数一般写入路由配置文件中router/index.js,当然你也可以写在main.js中

路由有三大钩子函数,如下

  • 全局守卫

    1. router.beforeEach全局前置

      这个钩子的回调中有三个参数,分别为to, from, next。通常我们可以用这个来判断用户是否登录,如果没有登录去其他页面就送回登录页面

      router.beforeEach((to, from, next) => {  
          if (to.path !== '/') { 
              const isLogin = localStorage.getItem('isLogin') // 读取isLogin
              if (isLogin) {
                  next()
              } else {
                  router.push('/login')
              }
          }
          next()
      })
      

      当然这仅仅是前端的判断规则,其实单单这个方法并不严谨,需要前后端一起配合才严谨,因为有些用户可能直接右键页面来到应用下给Local storage塞一个isLogin为true的值

      当然,你还可以用这个前置钩子设置页面的标题

      import { createWebHistory, createRouter } from 'vue-router'
      
      const routes = [
          {
              path: '/',
              name: 'home',
              component: () => import('../views/Home.vue'),
              meta: {
                  title: '首页'
              }
          },
          {
              path: '/about',
              name: 'about',
              component: () => import('../views/About.vue'),
              meta: {
                  title: '关于'
              }
          }
          
      ]
      
      const router = createRouter({
          history: createWebHistory(),
          routes
      })
      
      
      router.beforeEach((to, from, next) => { 
          document.title = to.meta.title
          if (to.path !== '/') { 
              const isLogin = localStorage.getItem('isLogin') 
              if (isLogin) {
                  next()
              } else {
                  alert('未登录,不许跳页面')
                  return 
              }
          }
          next()
      })
      
      export default router
      

      meta是专门用于存放一些参数信息,是路由的特殊标记

    2. router.beforeResolve全局解析

      解析钩子和全局前置区别不大,解析钩子是在路由被解析,代码被编译之前触发。

    3. router.afterEach全局后置

      这个钩子的回调函数只有两个参数,没有next。after就是路由跳转之后去干什么事情,用处很少。

    这三个钩子可以用跳远来形容,beforeEach是起跳前,beforeResolve是悬空中,afterEach是落地后,用的最多的钩子就是第一个beforeEach

  • 独享守卫

    刚刚的守卫是全局的,只要是路由跳转,都可以影响到。独享路由只能影响自身,配置方法如下,这里给about页面配置

    const routes = [
        {
            path: '/',
            name: 'home',
            component: () => import('../views/Home.vue'),
            meta: {
                title: '首页'
            }
        },
        {
            path: '/about',
            name: 'about',
            component: () => import('../views/About.vue'),
            meta: {
                title: '关于'
            },
            beforeEnter: (to, from, next) => {
                console.log(to, from);
                next()
            }
        }
        
    ]
    

    你可以在里面写逻辑,比如特定页面弹出广告

  • 组件内的守卫

    组件内的守卫写入指定的页面中,写之前记得引入。新语法只有下面这两个,以前还有一个onBeforeRouteEnter

  1. onBeforeRouteLeave

    离开页面前做一些操作,比如,离开页面前,弹出你确定想要离开

    import { onBeforeRouteLeave } from 'vue-router';
    
    onBeforeRouteLeave((to, from, next) => {  
        console.log(to, from);
        const flag = window.confirm('你确定要离开这个页面吗?')
        if (flag) {
            next()
        }
    })
    

    window.confirm()是js自带的弹出框

  2. onBeforeRouteUpdate

    如果两个页面之间共用了一个组件,并且互相跳转,就可以用这个Update方法写逻辑

keep-alive

在开发vue项目的时候,很多组件是没有必要再次渲染的。多个页面公用一个组件,跳转页面的时候就不需要再次渲染,就没必要再次加载公共组件的代码

因为跳转路由的时候页面内所有的组件都是会重新销毁加载的

keep-alive的作用就是用来包裹需要缓存的组件,留下缓存就是不会重新加载,起到一个性能优化的作用

这里我用两个页面首页,和关于页面,然后缓存首页模拟下,语法如下,写在App.vue

<template>
  <div>
    <nav>
      <router-link to="/">首页 | </router-link>
      <router-link to="/about">关于</router-link>
    </nav>

    <router-view v-slot="{ Component }">
      <keep-alive :include="['Home']">
        <component :is="Component" />
      </keep-alive>
    </router-view>
  </div>
</template>

<script setup>

</script>

<style lang="css" scoped></style>

我们可以在首页中写入钩子onActivatedonDeactivated测试下是否真被缓存了

<template>
    <div>
        <p>home page</p>
    </div>
</template>

<script setup>
import { onMounted, onActivated, onDeactivated } from 'vue';

onMounted(() => {
    console.log('home的onMounted');
})
onActivated(() => {   // 当被缓存的组件再次生效时触发
    console.log('home的onActivated');  
}) 
onDeactivated(() => {  // 当组件被缓存起来并离开时触发 
    console.log('home的onDeactivated');
})
</script>

<style lang="css" scoped>

</style>

第一次进入首页时,会触发onMounted,之后从其他页面再次进入时就不再触发onMounted,因为首页被缓存了起来,压根没有被卸载(卸载是默认的效果)

onActivated()

onActivated其实就是缓存版的onMounted,被缓存的组件加载时生效

onDeactivated()

onDeactivated其实就是缓存版的onUnmounted,被缓存的组件离开时生效

这两个钩子都不需要进行再次解析组件,因为针对的组件都是已经被缓存过的。就相当于你没扔掉,而是放进了一个口袋,用时拿起,不用时放入。

所以这两个钩子一定需要有keep-alive的出现,否则用不上

最后

vue里面的生命周期清除这些足够拿去面试了,其实面试官最想听你讲的就是onAcivated和onDeactivated,很容易理解

另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请”点赞+评论+收藏“一键三连,感谢支持!

本次学习代码已上传至本人GitHub学习仓库:github.com/DolphinFeng…

假如您也和我一样,在准备春招。欢迎加我微信Dolphin_Fung,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!