vue组件周期函数和路由周期函数

发布于 2024-03-07  211 次阅读


Vue.js 是一个流行的前端框架,用于构建用户界面和单页应用程序。在 Vue 2 中,组件的生命周期是非常重要的概念,它定义了组件从创建到销毁过程中的各个阶段。每个阶段都有相应的生命周期钩子函数,可以让开发者在不同阶段执行自定义逻辑。以下是 Vue 2 中的主要生命周期钩子函数:

  1. beforeCreate: 这是最早触发的钩子,在实例初始化之后,数据观测 (data observation) 和事件/侦听器配置之前被调用。

  2. created: 在实例创建完成后被立即调用。在这一步,实例已完成数据观测、属性和方法的运算,$el 属性目前尚不可见。

  3. beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。此时,模板或渲染函数尚未将数据渲染成 DOM。

  4. mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果根实例挂载了一个文档内元素,当 mounted 被调用时,组件已经在文档中。

  5. beforeUpdate: 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。

  6. updated: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件的 DOM 已经更新,所以现在可以执行依赖于 DOM 的操作。

  7. beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用,这是清理定时器或解绑全局事件监听器的好时机。

  8. destroyed: Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

理解这些生命周期钩子函数对于使用 Vue 2 开发高质量的应用程序至关重要,它们提供了在不同阶段管理组件的强大能力。
下面是一个 Vue 2 组件的示例,展示了如何在组件中使用各个生命周期钩子函数。这个示例包含了大部分常用的生命周期钩子,以及它们被触发的时机和一些典型的用途。

生命周期示例

<template>
  <div>
    <h1>Vue 生命周期示例</h1>
  </div>
</template>

<script>
export default {
  name: 'LifecycleExample',

  // beforeCreate 钩子:实例刚在内存中被创建,此时还未初始化 data 和 methods
  beforeCreate() {
    console.log('beforeCreate: 组件实例刚被创建,data 和 methods 尚未初始化');
  },

  // created 钩子:实例已创建完成,此时已初始化 data 和 methods,但尚未开始 DOM 渲染
  created() {
    console.log('created: 组件实例已创建完成,data 和 methods 已初始化,但未挂载 DOM');
  },

  // beforeMount 钩子:在挂载开始之前被调用,相关的 render 函数首次被调用。
  beforeMount() {
    console.log('beforeMount: 挂载开始之前,模板编译/挂载之前');
  },

  // mounted 钩子:实例被挂载后调用,此时可以访问到 DOM
  mounted() {
    console.log('mounted: 组件已挂载到 DOM 上,此时可以进行 DOM 操作');
  },

  // beforeUpdate 钩子:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前
  beforeUpdate() {
    console.log('beforeUpdate: 数据更新前,DOM 还未更新');
  },

  // updated 钩子:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子
  updated() {
    console.log('updated: 组件数据更新后,DOM 也随之更新');
  },

  // beforeDestroy 钩子:实例销毁之前调用
  beforeDestroy() {
    console.log('beforeDestroy: 组件销毁前调用,此时组件实例仍然完全可用');
  },

  // destroyed 钩子:Vue 实例销毁后调用
  destroyed() {
    console.log('destroyed: 组件销毁后调用,所有的事件监听器被移除,子实例也被销毁');
  }
}
</script>

<style>
/* 组件样式 */
</style>

在这个示例中,我们定义了一个名为 LifecycleExample 的 Vue 组件,并在其中实现了所有主要的生命周期钩子。每个钩子函数内部,我们通过 console.log 输出一条消息,以便于观察这些钩子函数的调用时机。

这些生命周期钩子提供了在不同阶段介入组件行为的能力,例如:

  • beforeCreatecreated 可以用来在组件初始化时进行数据或事件的设置。
  • beforeMountmounted 提供了在组件挂载到 DOM 前后执行代码的机会。
  • beforeUpdateupdated 允许在响应数据变化前后执行特定逻辑。
  • beforeDestroydestroyed 可以用于执行清理操作,比如取消事件监听或定时器。

理解和合理利用这些生命周期钩子,对于开发高质量的 Vue 应用至关重要。
在使用 Vue.js 开发单页应用时,通常会搭配 Vue Router 来管理页面路由。Vue Router 提供了多个导航守卫(也称为路由生命周期钩子),允许你在路由发生变化时执行逻辑,如权限验证、页面标题更新等。这些守卫可以分为全局守卫、路由独享的守卫和组件内的守卫。

全局路由守卫

  1. beforeEach: 注册一个全局前置守卫。这个守卫会在路由即将改变前触发。它可以决定是否继续执行路由或取消。

  2. beforeResolve: 注册一个全局解析守卫。这个守卫会在 beforeEach 之后调用,并且确保所有的异步组件和异步路由组件被解析之后调用。

  3. afterEach: 注册一个全局后置钩子。这个钩子会在路由改变完成后触发,不接受 next 函数也不会改变导航本身。

路由独享的守卫

  1. beforeEnter: 在路由配置上直接定义的守卫。它和 beforeEach 类似,但只作用于某个特定的路由。对于需要根据路由来变更行为的场景非常有用。

组件内的守卫

  1. beforeRouteEnter: 能够在渲染该组件的对应路由被 confirm 前调用。不能获取 this 组件实例,因为当守卫执行前,组件实例还没被创建。

  2. beforeRouteUpdate (2.2 新增): 在当前路由改变,但是该组件被复用时调用。举例来说,在使用动态路由参数时,同一个组件可以被多次复用。可以通过这个守卫访问组件实例 this

  3. beforeRouteLeave: 导航离开该组件的对应路由时调用。可以访问组件实例 this,并且可以通过返回 false 来取消导航。

这些守卫提供了强大的路由控制能力,使得在用户浏览应用时,开发者可以在不同阶段介入路由的变化过程,执行必要的逻辑处理。理解和合理利用这些路由生命周期函数,对于构建复杂且用户友好的 Vue 应用至关重要。
以下是一些基本的示例代码,以展示如何使用 Vue Router 的导航守卫。

全局路由守卫示例

// main.js 或 router.js 中
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  // 路由配置
})

// 全局前置守卫
router.beforeEach((to, from, next) => {
  console.log('全局前置守卫')
  // 根据业务逻辑决定是否要调用 next() 进行路由跳转
  next()
})

// 全局解析守卫
router.beforeResolve((to, from, next) => {
  console.log('全局解析守卫')
  next()
})

// 全局后置钩子
router.afterEach((to, from) => {
  console.log('全局后置钩子')
  // 不需要 next(),因为这个钩子不会改变导航本身
})

路由独享的守卫示例

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        console.log('路由独享的守卫')
        next()
      }
    }
  ]
})

组件内的路由守卫示例

// 在 Vue 组件内部
export default {
  name: 'MyComponent',
  data() {
    return {
      // 数据定义
    }
  },
  // 导航离开该组件的对应路由时调用
  beforeRouteLeave(to, from, next) {
    const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
    if (answer) {
      next()
    } else {
      next(false)
    }
  },
  // 在渲染该组件的对应路由被确认前调用
  beforeRouteEnter(to, from, next) {
    console.log('beforeRouteEnter')
    next()
  },
  // 在当前路由改变,但是该组件被复用时调用
  beforeRouteUpdate(to, from, next) {
    console.log('beforeRouteUpdate')
    next()
  }
}

以上示例展示了如何在 Vue 应用中使用 Vue Router 的导航守卫。记住,next() 函数是非常重要的,它决定了路由的执行流程。调用 next() 会执行下一个守卫,而 next(false) 会取消当前的导航。你还可以通过 next('/path')next({ path: '/path' }) 来重定向到另一个路由。