Code前端首页关于Code前端联系我们

一、创建阶段,beforeCreate 和 created 到底能干啥?

terry 20小时前 阅读数 14 #Vue

p>想学Vue2但被生命周期钩子搞晕?看着created、mounted这些名词一头雾水,不知道每个阶段干啥、怎么结合业务场景用?别慌,这篇文章把Vue2生命周期钩子拆成「创建→挂载→更新→销毁」四个核心阶段,再补充场景化钩子,用大白话+例子讲清楚每个钩子的作用、什么时候用,帮你从「背概念」到「会实操」~

Vue 实例从 new Vue() 开始,先进入创建阶段,这一步是给实例“搭骨架”,决定后续能调用哪些数据和方法。

  • beforeCreate:实例刚初始化,相当于“地基刚打好,内部线路还没铺”。data 里的变量、methods 里的方法都没绑定到实例上,你打印 this.xxx 全是 undefined,这一步基本用不上,了解时机即可。

  • created:实例完成“数据观测(把 data 变响应式)、事件配置”,相当于“房子水电通了,能住人了”。this 能访问 datamethods,是初始化数据的黄金时机——比如页面加载时发 Ajax 请求、初始化全局变量。

举个栗子:做个人中心页面,需要加载用户头像、昵称,在 created 里调接口最安全:

export default {
  data() { return { userInfo: {} } },
  created() { this.fetchUserInfo() }, // 能拿到 this,调用 methods
  methods: {
    fetchUserInfo() {
      axios.get('/api/user').then(res => {
        this.userInfo = res.data; // data 已被代理,能直接赋值
      });
    }
  }
};

为啥不在 beforeCreate 发请求?因为那时候 this.userInfo 都没绑定,调方法也会报错,created 是初始化数据的关键节点~

挂载阶段:beforeMount 和 mounted 怎么玩 DOM?

创建阶段结束后,Vue 要把模板(template)转换成真实 DOM 并渲染到页面,这就是挂载阶段

  • beforeMount:模板已编译成渲染函数,但 DOM 还没真正渲染到页面,此时页面上对应的 DOM 还是“虚拟”的,操作 DOM 没意义,所以这个钩子用得少,理解“准备挂载前的过渡”即可。

  • mounted:真实 DOM 已渲染完成,$el(Vue 实例对应的 DOM 元素)也存在了,这一步是操作真实 DOM 的安全区——比如初始化第三方插件(ECharts、富文本编辑器)、修改 DOM 样式/内容。

举个例子:做带进度条的组件,必须等 mounted 才能拿到 DOM 节点:

export default {
  data() { return { progress: 0 } },
  mounted() {
    const progressBar = this.$el.querySelector('.progress-bar');
    // 模拟进度条加载
    const timer = setInterval(() => {
      this.progress += 10;
      progressBar.style.width = this.progress + '%';
      if (this.progress >= 100) clearInterval(timer);
    }, 500);
  }
};

如果在 beforeMount 里写这段代码,根本找不到 .progress-bar 节点,因为 DOM 还没渲染~

更新阶段:beforeUpdate 和 updated 咋应对数据变化?

Vue 是响应式框架,数据变了页面会自动更新。更新阶段就是处理“数据变化→页面更新”的钩子。

  • beforeUpdate:数据已经改变,但 DOM 还没更新。this 里的数据是新的,页面显示的却是旧的,这个钩子适合“DOM 更新前记录旧状态”(实际用得少,主要是理解时机)。

  • updated:数据和 DOM 都完成更新,页面内容和 data 完全同步,这一步适合“DOM 更新后必须执行的操作”,比如统计元素位置、加动画收尾。

举个电商场景:购物车数量变化后,给数字加弹跳动画:

export default {
  data() { return { cartCount: 0 } },
  methods: {
    addToCart() { this.cartCount += 1; } // 数据变化,触发更新
  },
  updated() {
    const cartBadge = this.$el.querySelector('.cart-badge');
    cartBadge.classList.add('bounce'); // DOM 已更新,加动画
    setTimeout(() => { cartBadge.classList.remove('bounce'); }, 500);
  }
};

如果在 beforeUpdate 里加动画,DOM 还是旧的,数字没变化,动画就白加了。updated 是数据和 DOM 同步后的“操作安全区”~

销毁阶段:beforeDestroy 和 destroyed 咋“善后”?

当 Vue 实例被销毁(比如路由跳转、组件被 v-if 移除),进入销毁阶段,这一步要做“清理工作”,防止内存泄漏。

  • beforeDestroy:实例还没销毁,所有数据、方法都能用,此时要“清除副作用”——比如清定时器、解绑自定义事件、取消 Axios 请求。

  • destroyed:实例完全销毁,所有数据绑定、事件监听都被移除,这一步用得少,因为清理工作一般在 beforeDestroy 做,destroyed 更多是“确认销毁完成”的通知。

举个定时器的例子,不清理会内存泄漏:

export default {
  data() { return { timer: null } },
  mounted() {
    this.timer = setInterval(() => {
      console.log('每隔1秒执行');
    }, 1000);
  },
  beforeDestroy() {
    clearInterval(this.timer); // 销毁前清定时器,否则会一直跑
    this.timer = null;
  }
};

如果跳过 beforeDestroy 直接销毁,定时器会持续占用内存,页面越用越卡~

额外钩子:activated、deactivated、errorCaptured 是干啥的?

除了核心的 8 个钩子(创建 2 + 挂载 2 + 更新 2 + 销毁 2),Vue2 还有几个“场景化钩子”,针对性解决特定问题。

activated / deactivated(和 keep-alive 配合)

只有组件被 <keep-alive> 包裹时才会触发:

  • activated:组件从缓存中取出、重新显示时调用,适合“缓存组件切换后刷新数据”,Tab 切换时重新拉取当前 Tab 数据。
  • deactivated:组件被缓存(离开页面但没销毁)时调用,适合“暂停定时器、停止轮播”等临时暂停操作。

举个 Tab 切换的例子:

export default {
  activated() { this.fetchTabData(); }, // 切回 Tab 时刷新数据
  deactivated() { clearInterval(this.timer); } // 离开时暂停定时器
};

errorCaptured(错误捕获)

当组件树中某个组件抛出错误时触发,能捕获子组件的错误,返回 false 可阻止错误向上传播,适合做全局错误监控,比如记录错误信息、上报服务器。

示例:

export default {
  errorCaptured(err, instance, info) {
    // err:错误对象;instance:出错的组件实例;info:错误发生的钩子(如 mounted)
    console.log('捕获到错误:', err, '在组件:', instance, '钩子:', info);
    return false; // 阻止错误向上冒泡
  }
};

生命周期执行顺序总结(附“人生 analogy”)

把 Vue 实例的生命周期想象成“出生→长大→变化→死亡”,执行顺序是:

beforeCreate(刚孕育)→ created(五脏俱全)→ beforeMount(穿衣服准备出门)→ mounted(正式出门,能互动)→(数据变化时)beforeUpdate(换衣服前)→ updated(换好衣服)→(实例销毁时)beforeDestroy(临终前交代后事)→ destroyed(尘归尘)

记住这个顺序,写代码时就能精准判断“哪一步该做什么”~

新手常踩的坑:这些场景别用错钩子!

理解时机是基础,避开这些坑才能写出健壮的代码:

  1. 在 beforeCreate 里操作 data/methods → 必错!此时数据还没绑定,this.xxx 全是 undefined
  2. mounted 里拿不到 DOM 元素 → 检查是不是异步渲染?比如子组件没加载完、DOM 被 v-if 控制(v-iffalse 时 DOM 不存在),可以用 $nextTick 延迟执行:
    mounted() {
      this.$nextTick(() => {
        const el = this.$el.querySelector('.async-el'); // 确保 DOM 完全渲染
      });
    }
  3. 忘记在 beforeDestroy 清理资源 → 定时器、自定义事件(如 window.addEventListener)不清理,会导致内存泄漏,页面越用越卡。
  4. 把 mounted 当“整个页面加载完成”mounted 只代表当前组件的 DOM 渲染完成,不是整个页面,如果要等所有资源加载完,得用 window.onload 或全局钩子。

掌握生命周期,写出更“丝滑”的 Vue 代码

Vue2 生命周期钩子的本质,是在实例的不同阶段“插桩”,让你精准控制“什么时候做什么事”,理解每个钩子的执行时机,结合业务场景(比如初始化数据→created,操作 DOM→mounted,清资源→beforeDestroy),代码就会更高效、更少 Bug。

现在再看 createdmounted 这些钩子,是不是清晰多了?下次写组件时,先想“这个逻辑该在哪个阶段执行”,按阶段做事,Vue 开发就会顺很多~

如果还有疑问(多个组件嵌套时生命周期执行顺序是啥?”“keep-alive 钩子怎么和核心钩子配合?”),留言告诉我,下次展开讲~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门