《探索 JS 生命周期函数的神秘节奏》

162 阅读5分钟

《探索 JS 生命周期函数的神秘节奏》

当我们走进 JavaScript 的奇妙世界,生命周期函数就像是这个世界里的重要规则。它们决定了代码在什么时候做什么事情,就像我们一天中在不同时间有不同的任务一样。 这些函数虽然看不见摸不着,但却在幕后默默地发挥着巨大的作用。它们让我们的程序能够有条不紊地运行,确保数据得到正确处理,功能得以顺利实现。 如果我们能搞清楚这些生命周期函数,就能更好地掌控我们的代码,让我们的程序跑得更顺、做得更多!现在,就让我们一起去探索它们的奥秘吧!

组件运行前

  1. beforeCreate

    • 这是组件生命周期的第一个阶段。
    • 组件实例刚刚被创建,此时还没有进行数据的初始化和响应式设置,也不能访问组件的 datacomputed 属性和 methods 方法。
    • 通常很少在这个阶段进行操作,因为可用的功能非常有限。
  2. created

    • 在这个阶段,组件已经完成了数据的初始化和响应式设置。
    • 可以访问组件的 data 和 computed 属性,也可以执行一些与数据相关的操作,比如发送异步请求获取数据、对数据进行一些预处理等。
    • 但组件还没有被挂载到 DOM 上,所以无法操作 DOM 元素。
  3. beforeMount

    • 此时模板已经编译完成,但还没有实际渲染到页面的 DOM 中。
    • 可以在这个阶段进行一些最后的准备工作,例如在挂载之前对数据进行一些微调。
  4. mounted

    • 组件已经被成功挂载到 DOM 上,此时可以访问到真实的 DOM 元素。

    • 这是一个常用的阶段,常用于执行与 DOM 操作相关的任务,比如初始化一些基于 DOM 的插件、添加事件监听器等。

    • 一般来说,如果组件需要与 DOM 进行交互,大多数操作会在这个阶段进行。

在组件运行过程中,如果数据发生变化:

  1. beforeUpdate

    • 当组件的数据发生变化,并且即将重新渲染之前,会触发这个钩子函数。
    • 可以在这里获取到更新之前的组件状态,以便进行一些比较或处理。
  2. updated

    • 数据更新完成,并且组件的 DOM 也已经重新渲染完毕后触发。

    • 可以在这个阶段对更新后的 DOM 进行操作,但要注意避免在此处进行过多的复杂操作,以免导致性能问题。

当组件不再需要使用,即将被销毁时:

  1. beforeDestroy

    • 在组件销毁之前触发。
    • 可以在这里执行一些清理操作,例如解除事件监听器、清除定时器、取消订阅等,以避免内存泄漏。
  2. destroyed

    • 组件已经被完全销毁,相关的资源都已释放。

举个例子,假设我们有一个显示用户信息的组件:

在 created 阶段,我们可以发送请求获取用户数据。在 mounted 阶段,我们可以根据获取到的数据动态地修改 DOM 元素的样式或内容。当用户信息更新时,会依次触发 beforeUpdate 和 updated 钩子。当组件不再使用要被销毁时,在 beforeDestroy 中清理相关的资源。

beforeCreate 和 created 生命周期钩子函数的 Vue 示例:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 生命周期示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    {{ message }}
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        message: '初始消息'
      },
      beforeCreate() {
        console.log('beforeCreate:实例初始化之前,无法访问 data 中的数据,message: ' this.message); 
      },
      created() {
        console.log('created:实例创建完成,可以访问 data 中的数据,message: ' this.message); 
      }
    });
  </script>
</body>

</html>
  • beforeCreate 钩子函数中,无法访问组件的 data 数据,所以 console.log 输出的 this.message 是未定义的。
  • created 钩子函数中,已经可以访问 data 中的数据,能正确输出 message 的值,即 "初始消息"。

beforeMount 和 mounted 生命周期钩子函数的 Vue 示例:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 生命周期示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <h1>{{ message }}</h1>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        message: '初始消息'
      },
      beforeMount() {
        console.log('beforeMount: 模板编译完成,即将挂载到 DOM,但还未挂载');
      },
      mounted() {
        console.log('mounted: 模板已挂载到 DOM');
        // 可以在此获取和操作 DOM 元素
        const h1Element = document.querySelector('h1');
        h1Element.style.color ='red';
      }
    });
  </script>
</body>

</html>
  • beforeMount 钩子函数在模板编译完成,但还没有实际渲染到页面的 DOM 中时被调用。
  • mounted 钩子函数在组件已经被成功挂载到 DOM 上之后被调用。此时可以访问真实的 DOM 元素,并进行相应的操作,比如在示例中修改了 h1 元素的文字颜色。

beforeUpdate 和 updated 钩子函数的 Vue 示例:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 生命周期示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <button @click="increment">点击增加</button>
    <p>{{ count }}</p>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        count: 0
      },
      methods: {
        increment() {
          this.count++;
        }
      },
      beforeUpdate() {
        console.log('beforeUpdate: 数据即将更新,更新前的 count 值为', this.count);
      },
      updated() {
        console.log('updated: 数据更新完成,更新后的 count 值为', this.count);
      }
    });
  </script>
</body>

</html>

当点击“点击增加”按钮时,count 值增加,从而触发数据更新。

  • beforeUpdate 钩子函数在数据变化即将重新渲染组件之前被调用,可以获取到更新前的组件状态。

  • updated 钩子函数在数据更新且 DOM 重新渲染完毕后被触发。

需要注意的是,在 updated 钩子函数中应尽量避免复杂的 DOM 操作,因为频繁的数据更新可能导致性能问题。如果有大量的复杂 DOM 操作需求,可能需要考虑优化数据结构或使用更高效的算法。

beforeDestroy 和 destroyed 钩子函数的 Vue 示例:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 生命周期示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <button @click="destroyComponent">销毁组件</button>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        timer: null
      },
      methods: {
        startTimer() {
          this.timer = setInterval(() => {
            console.log('定时器在运行...');
          }, 1000);
        },
        destroyComponent() {
          this.$destroy();
        }
      },
      beforeCreate() {
        console.log('beforeCreate: 实例初始化之前');
      },
      created() {
        console.log('created: 实例创建完成');
        this.startTimer();
      },
      beforeMount() {
        console.log('beforeMount: 即将挂载');
      },
      mounted() {
        console.log('mounted: 已挂载');
      },
      beforeUpdate() {
        console.log('beforeUpdate: 数据即将更新');
      },
      updated() {
        console.log('updated: 数据更新完成');
      },
      beforeDestroy() {
        console.log('beforeDestroy: 组件即将销毁,清除定时器');
        clearInterval(this.timer);
      },
      destroyed() {
        console.log('destroyed: 组件已销毁');
      }
    });
  </script>
</body>

</html>
  • 点击“销毁组件”按钮时,会调用 $destroy 方法触发组件的销毁过程。
  • beforeDestroy 钩子函数中,清除了之前创建的定时器,以避免内存泄漏。
  • destroyed 钩子函数表示组件已经完全销毁,相关资源释放

总结

Vue 的生命周期钩子函数为开发者提供了在组件不同阶段进行特定操作的时机,以便更有效地管理组件的创建、更新和销毁过程,实现更高效和可靠的应用开发。