> 文章列表 > 【三十天精通Vue 3】第八天 Vue 3 生命周期钩子详解

【三十天精通Vue 3】第八天 Vue 3 生命周期钩子详解

【三十天精通Vue 3】第八天 Vue 3 生命周期钩子详解

请添加图片描述

✅创作者:陈书予
🎉个人主页:陈书予的个人主页
🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区
🌟专栏地址: 三十天精通 Vue 3

文章目录

  • 引言
    • 一、Vue 3 生命周期钩子概述
      • 1.1 生命周期钩子的简介
      • 1.2 生命周期钩子的分类
      • 1.3 生命周期钩子的语法
    • 二、Vue 3 组件的生命周期钩子
      • 2.1 beforeCreate 钩子
      • 2.2 created 钩子
      • 2.3 beforeMount 钩子
      • 2.4 mounted 钩子
      • 2.5 beforeUpdate 钩子
      • 2.6 updated 钩子
    • 三、Vue 3 组件的局部生命周期钩子
      • 3.1 beforeMount 钩子
      • 3.2 mounted 钩子
      • 3.3 beforeUpdate 钩子
      • 3.4 updated 钩子
    • 四、Vue 3 生命周期钩子的应用场景
      • 4.1 组件的创建和更新
        • 4.1.1 beforeCreate 和 created
        • 4.1.2 beforeMount 和 mounted
        • 4.1.3 beforeUpdate 和 updated
      • 4.2 组件的数据更新
        • 4.2.1 beforeUpdate 和 updated
      • 4.3 组件的事件处理
        • 4.3.1 beforeMount 和 mounted
    • 五、Vue 3 生命周期钩子的常见问题及解决方案
      • 5.1 生命周期钩子的执行顺序问题
      • 5.2 生命周期钩子的执行时机问题
      • 5.3 生命周期钩子的性能问题

引言

Vue 3 生命周期钩子是 Vue 3 新增的一个重要特性,它可以帮助开发者更加精细地控制组件的创建和更新,从而提高组件的性能和响应速度。今天,我们将详细介绍 Vue 3 生命周期钩子的概念、分类、语法和应用,以及生命周期钩子常见的问题和解决方案。

一、Vue 3 生命周期钩子概述

1.1 生命周期钩子的简介

生命周期钩子是 Vue 3 新增的一种特性,它允许开发者在组件的创建和更新过程中执行自定义代码。在 Vue 3 中,组件的生命周期分为七个钩子函数,分别是 beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy 和 destroyed。这些钩子函数在不同的生命周期阶段执行,可以用于更新组件、处理事件、处理数据等

1.2 生命周期钩子的分类

Vue 3 的生命周期钩子可以分为三类:

  • 组件生命周期钩子:

包括 beforeCreate、created、beforeMount、mounted、beforeUpdate、updated 和 beforeDestroy 七个钩子函数,它们分别出现在组件的创建和更新过程中。

  • 局部生命周期钩子:

包括 beforeMount、mounted、beforeUpdate 和 updated 四个钩子函数,它们分别出现在组件的局部挂载、更新、更新前后和卸载过程中。

  • 事件生命周期钩子:

包括 beforeMount、mounted、beforeUpdate 和 updated 四个钩子函数,它们分别出现在组件的局部挂载、更新、更新前后和卸载过程中,可以用于处理事件。

1.3 生命周期钩子的语法

生命周期钩子语法非常简单,只需要在组件的声明部分添加生命周期钩子函数名,并在函数名上面添加一个双冒号 ::。例如,下面的代码展示了一个包含 beforeCreate 钩子的组件:

export default {  name: 'MyComponent',  props: {  value: {  type: String,  default: ''  }  },  data() {  return {  message: ''  }  },  beforeCreate() {  console.log(`Before create, value: ${this.value}`);  }  
}

二、Vue 3 组件的生命周期钩子

2.1 beforeCreate 钩子

beforeCreate 是 Vue 3 组件实例刚刚被创建时执行的钩子函数。在这一阶段,我们通常需要执行一些初始化操作,例如从服务器获取数据或者从缓存中检索数据。以下是一个使用 beforeCreate 钩子实现从服务器获取数据的示例代码:

import { created, beforeCreate } from 'vue';export default {  created() {  this.$http.get('data.json')  .then(response => {  this.data = response.data;  });  },  
};  

在这个示例中,我们在组件实例被创建时使用$http 方法从服务器获取数据。获取成功后,我们将数据存储在组件实例的 data 属性中。

2.2 created 钩子

created 是 Vue 3 组件实例已经创建完成并加载完毕时执行的钩子函数。在这一阶段,我们可以访问组件实例的 data、props、methods 等数据,但是$el 属性还未被创建,还不能访问 DOM 节点。以下是一个使用 created 钩子实现获取数据后更新 UI 的示例代码:

import { created } from 'vue';export default {  created() {  this.data = 'Hello Vue!';  },  
};  

在这个示例中,我们在组件实例被创建时将数据设置为"Hello Vue!",然后通过 data 属性访问数据,并将其显示在 UI 中。

2.3 beforeMount 钩子

beforeMount 是 Vue 3 组件模板挂载开始时执行的钩子函数。在这一阶段,我们通常需要执行一些模板挂载时需要的操作,例如设置 class、绑定事件等。以下是一个使用 beforeMount 钩子实现在组件模板中使用 class 的示例代码:

import { beforeMount } from 'vue';export default {  beforeMount() {  this.classList.add('active');  },  
};  

在这个示例中,我们在组件模板中使用 class 属性来设置一个状态,然后在 beforeMount 钩子函数中使用 classList 方法将状态设置为 active。

2.4 mounted 钩子

mounted 是 Vue 3 组件模板已经被渲染到 DOM 中时执行的钩子函数。在这一阶段,我们可以访问 DOM 节点,可以执行任何与 DOM 相关的操作。以下是一个使用 mounted 钩子实现在组件模板中使用 DOM 节点的示例代码:

import { mounted } from 'vue';export default {  mounted() {  const $el = this.$el;  const textContent = $el.textContent;  console.log(`The element is mounted with: ${textContent}`);  },  
};  

在这个示例中,我们在组件实例被渲染到 DOM 中时访问$el 属性,并获取 DOM 节点的文本内容,然后将文本内容打印到控制台中。

2.5 beforeUpdate 钩子

beforeUpdate 钩子函数中,我们可以更新组件的 UI,例如更改文本、更改样式或者重新加载数据。以下是一个使用 beforeUpdate 钩子实现更新 UI 的示例代码:

import { beforeUpdate } from 'vue';export default {  methods: {  updateUI() {  // 更新文本内容  this.textContent = 'Hello Vue 3!';  // 更新样式  this.classList.add('new-class');  // 重新加载数据  this.$fetch('/api/data').then(response => {  this.data = response.data;  });  }  }  
};  

在这个示例中,我们在 beforeUpdate 钩子函数中更新文本内容、样式以及重新加载数据。当数据更新时,组件的 UI 也会随之更新。

2.6 updated 钩子

updated 是 Vue 3 组件数据更新后执行的钩子函数。在这一阶段,我们通常需要执行一些更新操作,例如更新 UI、重新加载数据等。以下是一个使用 updated 钩子实现更新 UI 的示例代码:

import { updated } from 'vue';export default {  data() {  return {  textContent: 'Hello Vue 3!',  classList: ['active']  };  },  methods: {  updateUI() {  // 更新文本内容  this.textContent = 'Hello Vue 3!';  // 更新样式  this.classList.remove('active');  // 重新加载数据  this.$fetch('/api/data').then(response => {  this.data = response.data;  });  }  }  
};  

在这个示例中,我们在 updated 钩子函数中更新文本内容、样式以及重新加载数据。当数据更新时,组件的 UI 也会随之更新。

三、Vue 3 组件的局部生命周期钩子

3.1 beforeMount 钩子

beforeMount 钩子是在组件模板挂载开始之前执行的生命周期钩子。在 beforeMount 钩子中,我们可以执行一些与模板挂载相关的操作,例如设置 class、绑定事件等。以下是一个使用 beforeMount 钩子实现在组件模板中使用 class 的示例代码:

import { beforeMount } from 'vue';export default {  methods: {  addClassName() {  this.classList.add('active');  }  },  beforeMount() {  this.classList.add('ready');  }  
};  

在这个示例中,我们在组件模板中使用 class 属性来设置一个状态,然后在 beforeMount 钩子函数中使用 classList 方法将状态设置为 active。

3.2 mounted 钩子

mounted 钩子是在组件模板已经被渲染到 DOM 中之后执行的生命周期钩子。在 mounted 钩子中,我们可以访问 DOM 节点,并执行任何与 DOM 相关的操作。以下是一个使用 mounted 钩子实现在组件模板中使用 DOM 节点的示例代码:

import { mounted } from 'vue';export default {  mounted() {  const $el = this.$el;  const textContent = $el.textContent;  console.log(`The element is mounted with: ${textContent}`);  }  
};  

在这个示例中,我们在组件模板中使用 $el 属性访问 DOM 节点,并使用 textContent 方法获取文本内容。

3.3 beforeUpdate 钩子

beforeUpdate 钩子是 Vue 3 组件数据更新时执行的生命周期钩子,但模板并没有重新渲染。在 beforeUpdate 钩子中,我们可以执行一些更新操作,例如更新组件的 UI、重新加载数据等。以下是一个使用 beforeUpdate 钩子实现更新组件 UI 的示例代码:

import { beforeUpdate } from 'vue';export default {  methods: {  updateUI() {  this.textContent = 'Hello Vue 3!';  this.$fetch('/api/data').then(response => {  this.data = response.data;  });  }  },  beforeUpdate() {  this.textContent = 'Hello Vue 3!';  }  
};  

在这个示例中,我们在 beforeUpdate 钩子函数中更新文本内容、样式以及重新加载数据。当数据更新时,组件的 UI 也会随之更新。

3.4 updated 钩子

updated 生命周期钩子在组件实例被更新时执行,例如在组件中使用 v-model 指令绑定的值更新时,或者在使用 watch 监听数据变化时。在 updated 生命周期钩子中,可以更新组件的状态或者执行其他操作,以确保组件的响应式数据与前端视图保持同步。

下面是一个示例代码,展示了如何在 Vue 3 中使用 updated 生命周期钩子更新组件状态:

import { created, updated } from 'vue'export default {    name: 'MyComponent',    data() {    return {    count: 0    }    },    created() {    this.count = this.count + 1    },    updated() {    console.log(`Component updated with count: ${this.count}`)    }    
}

在上面的代码中,我们在 created 生命周期钩子中初始化 count 变量,并在 updated 生命周期钩子中更新 count 变量。当 count 变量的数据更新时,updated 生命周期钩子将会被执行,从而更新组件状态。

需要注意的是,updated 生命周期钩子并不会在组件实例的 mounted 生命周期钩子之后执行,而是在组件实例的 created 生命周期钩子之后执行。因此,如果需要在组件实例的 mounted 生命周期钩子之后更新组件状态,可以使用 updated 生命周期钩子。

四、Vue 3 生命周期钩子的应用场景

4.1 组件的创建和更新

组件的创建和更新是 Vue 3 生命周期钩子的重要应用场景之一。在 Vue 3 中,组件的创建和更新是由生命周期钩子来完成的。以下是几个常用的生命周期钩子:

4.1.1 beforeCreate 和 created

beforeCreate 和 created 是组件创建过程中的两次关键事件。在 beforeCreate 中,你可以执行一些前置操作,例如设置组件实例的属性和数据等。在 created 中,你可以执行一些后置操作,例如加载组件所需的数据等。

以下是一个示例代码:

import { beforeCreate, created } from 'vue'export default {  beforeCreate() {  console.log('Before create')  },  created() {  console.log('After create')  }  
}

4.1.2 beforeMount 和 mounted

beforeMount 和 mounted 是组件挂载过程中的两次关键事件。在 beforeMount 中,你可以执行一些前置操作,例如设置组件的初始渲染函数等。在 mounted 中,你可以执行一些后置操作,例如处理组件的数据等。

以下是一个示例代码:

import { beforeMount, mounted } from 'vue'export default {  beforeMount() {  console.log('Before mount')  },  mounted() {  console.log('After mount')  }  
}

4.1.3 beforeUpdate 和 updated

beforeUpdate 和 updated 是组件更新过程中的两次关键事件。在 beforeUpdate 中,你可以执行一些前置操作,例如更新组件的数据等。在 updated 中,你可以执行一些后置操作,例如处理组件更新后的数据等。

以下是一个示例代码:

import { beforeUpdate, updated } from 'vue'export default {  beforeUpdate( prevData, prev prevData2 ) {  console.log('Before update')  },  updated( data ) {  console.log('After update')  }  
}

4.2 组件的数据更新

组件的数据更新也是 Vue 3 生命周期钩子的重要应用场景之一。在 Vue 3 中,组件的数据更新是由更新生命周期钩子来完成的。以下是几个常用的更新生命周期钩子:

4.2.1 beforeUpdate 和 updated

beforeUpdate 和 updated 是组件更新过程中的两次关键事件。在 beforeUpdate 中,你可以执行一些前置操作,例如更新组件的数据等。在 updated 中,你可以执行一些后置操作,例如处理组件更新后的数据等。

以下是一个示例代码:

import { beforeUpdate, updated } from 'vue'export default {  data() {  return {  count: 0  }  },  beforeUpdate() {  console.log('Before update')  this.count = this.count + 1  },  updated( data ) {  console.log('After update')  console.log(this.count)  }  
}

4.3 组件的事件处理

组件的事件处理也是 Vue 3 生命周期钩子的重要应用场景之一。在 Vue 3 中,组件的事件处理是由事件生命周期钩子来完成的。以下是几个常用的事件生命周期钩子:

4.3.1 beforeMount 和 mounted

beforeMount 和 mounted 是组件挂载过程中的两次关键事件。在 beforeMount 中,你可以监听事件并在事件触发时执行一些前置操作。在 mounted 中,你可以监听事件并在事件触发时执行一些后置操作。

以下是一个示例代码:

import { beforeMount, mounted } from 'vue'export default {  beforeMount() {  console.log('Before mount')  },  mounted() {  console.log('After mount')  // 可以在这里监听事件并执行一些操作  }  
},// 事件监听  
onEvent() {  console.log('Event trigger')  
}

五、Vue 3 生命周期钩子的常见问题及解决方案

5.1 生命周期钩子的执行顺序问题

在 Vue 3 中,生命周期钩子的执行顺序是按照以下规则进行的:

  1. 根组件的生命周期钩子先被执行,即 <root> 标签下的组件的生命周期钩子先被执行。
  2. 然后,根组件的子组件的生命周期钩子依次被执行。
  3. 最后,所有被虚拟 DOM 更新的组件的生命周期钩子被执行。

这个规则有助于我们了解 Vue 3 组件生命周期的工作原理,但是在某些情况下,这个规则可能会导致一些问题。例如,如果我们在子组件中使用 mounted 钩子函数来更新父组件的值,那么父组件的 beforeMount 钩子函数不会被执行,因为在子组件挂载之前,父组件已经被虚拟 DOM 更新了。

解决方案:对于按照上述顺序执行的生命周期钩子,我们可以通过使用 vue-router 中的 beforeMount 钩子函数来更新路由参数,从而避免在子组件挂载之前更新父组件的值。

import { navigate } from 'vue-router';export default {  methods: {  async beforeMount() {  await this.$nextTick(); // 确保页面加载完成后再更新路由参数  navigate('/route-name', { query: this.$route.query });  }  }  
}

在这个例子中,beforeMount 钩子函数会在子组件挂载之前被执行,然后会等待页面加载完成后,再更新路由参数。这样做可以避免在子组件挂载之前更新父组件的值,从而保证父组件的 mounted 钩子函数能够正常执行。

5.2 生命周期钩子的执行时机问题

在 Vue 3 中,生命周期钩子函数的执行时机是非常灵活的,可以根据需要进行自定义。例如,我们可以通过在父组件中使用 beforeMount 钩子函数来监听子组件挂载的时机,从而在子组件挂载之前执行一些操作。

但是,有时候我们的生命周期钩子函数的执行时机不够准确,可能会出现一些问题。例如,如果我们在子组件中使用 mounted 钩子函数来更新父组件的值,但是父组件的 beforeMount 钩子函数没有在子组件挂载之前执行,那么子组件的 mounted 钩子函数很可能会在父组件的 mounted 钩子函数之后执行,从而导致一些不可预知的结果。

解决方案:我们可以通过使用 beforeMountmounted 两个钩子函数来确保生命周期钩子函数的执行时机准确。在子组件中使用 mounted 钩子函数来更新父组件的值,确保在父组件的 mounted 钩子函数之前执行。

import { navigate } from 'vue-router';export default {  methods: {  async beforeMount() {  await this.$nextTick(); // 确保页面加载完成后再更新路由参数  navigate('/route-name', { query: this.$route.query });  },  mounted() {  // 更新父组件的值  }  }  
}

在这个例子中,beforeMount 钩子函数会在子组件挂载之前被执行,然后会等待页面加载完成后,再更新路由参数。而 mounted 钩子函数则会在子组件挂载完成后被执行,从而确保父组件的 mounted 钩子函数能够在此之前执行。

5.3 生命周期钩子的性能问题

由于 Vue 3 中的生命周期钩子是异步执行的,因此在处理大量实例时,可能会导致性能问题。以下是一些优化生命周期钩子性能的方法:

  1. 避免在生命周期钩子中执行耗时操作

在生命周期钩子中,避免在执行耗时操作,例如网络请求、计算、监听事件等。这些操作应该被避免或者在最必要时进行。可以通过将耗时操作移动到创建或更新实例之前,或者使用异步操作来避免这些问题。

  1. 缓存生命周期钩子结果

在多次使用相同的生命周期钩子时,应该缓存结果,避免重复执行。例如,在 created 生命周期钩子中,可以缓存 this.$routerthis.$root 等对象,避免重复计算。

  1. 避免在生命周期钩子中创建新对象

在生命周期钩子中,应该避免创建新的对象,例如在 mounted 生命周期钩子中创建新的数组或对象。这可能会导致性能问题,因为创建新对象需要消耗内存和时间。可以通过使用已有的对象或使用对象池来避免这些问题。

下面是一个示例代码,展示了如何在 Vue 3 中使用生命周期钩子优化性能:

import { created, beforeCreate, mounted, beforeDestroy, destroyed } from 'vue'const delay = ms => new Promise(resolve => setTimeout(resolve, ms))export default {  name: 'MyComponent',  data() {  return {  count: 0  }  },  生命周期钩子优化:{  created() {  this.count = this.count + 1  },  beforeCreate() {  delay(1000).then(() => {  this.count = 0  })  },  mounted() {  console.log(`Component mounted with count: ${this.count}`)  },  beforeDestroy() {  console.log(`Component beforeDestroy with count: ${this.count}`)  },  destroyed() {  console.log(`Component destroyed with count: ${this.count}`)  }  }  
}

在上面的代码中,我们使用 createdbeforeCreate 生命周期钩子来在实例创建时执行一些操作,使用 mountedbeforeMount 生命周期钩子来在实例挂载时执行一些操作,使用 beforeDestroydestroyed 生命周期钩子来在实例销毁时执行一些操作。我们还使用了 生命周期钩子优化 选项来缓存一些对象,避免重复计算,并且避免在 createdmounted 生命周期钩子中创建新的对象。