钩子函数是什么意思_聊聊 beforeUnmount/unMounted 生命周期钩子函数

本文详细介绍了 Vue.js 3.0 中的 beforeUnmount 和 unMounted 生命周期钩子函数,阐述了它们的区别以及在实际应用中的常见场景,如清理定时器、解绑全局事件和管理第三方库资源。强调理解生命周期并适时执行清理逻辑的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hello,各位小伙伴,接下来的一段时间里,我会把我的课程《Vue.js 3.0 核心源码解析》中问题的答案陆续在我的公众号发布,由于课程的问题大多数都是开放性的问题,所以我的答案也不一定是标准的,仅供你参考喔。

本期的问题:如果你想在路由组件切换的时候,取消组件正在发送的异步 Ajax 请求,那你应该在哪个生命周期写这个逻辑呢?

这个问题回答起来其实很简单,因为在路由组件切换的时候,被切换的组件会执行 beforeUnmountunMounted 钩子函数,所以在这俩生命周期钩子函数内部去执行取消异步 Ajax 请求的逻辑都可以。

如果我是面试官,问了这道题,你仅仅知道上述答案是不够的,因为我还会继续问:beforeUnmountunMounted 有什么区别,我们通常有哪些场景需要在 beforeUnmount 或者是 unMounted 里去写逻辑,以及为什么要这么做。

这种刨根问底的手法面试官在面试中经常会用到,目的在考察候选人对知识的掌握程度,所以仅仅靠背答案是不靠谱的,你需要深入了解这些知识点。

那么接下来,我们就来一一解答这几个问题,希望对你有所启发和帮助。

beforeUnmount 和 unMounted 的区别

先看一张图回顾一下 Vue.js 3.0 组件的生命周期:

1091f2f1ece5b05acf7c11b882d56726.png

其中 beforeUnmount 发生在组件 unmount 之前,unMounted 发生在组件 unmount 之后,而 unmount 函数做的事情,就是执行组件自身的一些清理逻辑、递归销毁子组件,进而把组件下面所有的 DOM 也全部移除了。

因此,当我们执行的 beforeUnmount 的时候,还是可以访问组件内部的 DOM 的,如果你的代码逻辑依赖 DOM,那么就必须在 beforeUnmount 钩子函数中执行。

此外,Vue.js 只能在 unmount 函数中做一些组件自身的内存清理,而对于用户的一些自定义操作所占用的内存,是不会清理的。

beforeUnmount 和 unMounted 的常见应用场景

因此,我们通常会利用 beforeUnmount 或者是 unMounted 钩子函数主动执行一些清理操作,下面我列几个常见的应用场景:

  • 定时器

假设你有一个计数组件,每秒加一,最简单的实现就是定义一个定时器,如下:

export default {
  setup() {
    let timer
    const count = ref(0)
    onMounted(()=>{
      timer = setInterval(()=>{
        count.value++
      }, 1000)
    })
    
    return {
      count
    }
  }
}

我们在 onMounted 钩子函数里用 setInterval 函数创建了一个定时器 timer,如果这个组件被销毁了,定时器是不会主动销毁的,也就造成了内存泄漏。

因此需要你在 beforeUnmount 或者 unMounted 钩子函数中主动清理定时器,如下:

export default {
  setup() {
    let timer
    const count = ref(0)
    onMounted(()=>{
      timer = setInterval(() => {
        count.value++
      }, 1000)
    })
    
    onBeforeUnmount(()=> {
      clearInterval(timer)
    })
    
    return {
      count
    }
  }
}
  • 全局注册事件

有些时候,我们需要在组件中监听某些全局事件,如下:

export default {
  setup() {
    onMounted(()=>{
      window.addEventListener('resize', onResize)
    })
   
    function onResize() {
      // 做一些 DOM 操作,数据更新等
    }
  }
}

我们在 onMounted 钩子函数里监听了全局的 resize 事件,当窗口大小改变的时候,就会执行事件函数 onResize,如果这个组件被销毁了,这个全局事件是不会主动解绑的。

因此需要你在 beforeUnmount 或者 unMounted 钩子函数中主动解绑事件,如下:

export default {
  setup() {
    onMounted(()=>{
      window.addEventListener('resize', onResize)
    })
    
    onBeforeUnmount(()=> {
      window.removeEventListener('resize', onResize)
    })
   
    function onResize() {
      // 做一些 DOM 操作,数据更新等
    }
  }
}

注意这里不能用匿名函数,因为 addEventListenerremoveEventListener 监听的事件函数需要指向同一个函数指针。

  • 第三方库

还有很多时候,我们会依赖一些第三方库辅助开发,而这些第三方库往往都会暴露一些 API 来做一些库内部的清理操作。

比如我们在移动端常用的 BetterScroll,就提供了清理的 API,我们可以这么使用它:

export default function useScroll(wrapperRef, options) {
  const scroll = ref(null)

  onMounted(() => {
    scroll.value = new BScroll(wrapperRef.value, options)
  })

  onUnmounted(() => {
    scroll.value.destroy()
  })

  return scroll
}

为了独立 BetterScroll 的逻辑,我们定义了 useScrollhook 函数,在这里我们仍然可以使用 Vue.js 提供的生命周期函数。

由于 BetterScroll 的初始化依赖容器的 DOM,所以我们在 onMounted 内部执行它的初始化逻辑。相应的,这次我们在 onUnmounted 内部执行 BS 实例的 destory 方法,这样就避免了组件销毁后 BS 实例内部带来的内存泄漏。

总结

在大多数情况下,我们使用 beforeUnmount 或者 unMounted 钩子函数都可以执行一些清理逻辑,至于用什么在于你的清理逻辑中有没有依赖 DOM,如果不依赖那么两者皆可。

此外,有些时候我们清理内存也并不一定依赖这俩个生命周期,你需要培养相关的意识,在合适的时机去做合适的事情。

我出这个题主要是希望你能做到以下两点:

  1. 从源码层面探索,了解 beforeUnmountunMounted 的差异。

  2. 从应用层面了解 beforeUnmountunMounted 应用场景,并学以致用。

要记住,分析和思考的过程远比答案重要。

### 生命周期函数钩子函数的区别 在编程领域,尤其是前端开发中,**生命周期函数**和**钩子函数**是两个经常被提及的概念。尽管它们在某些方面有交集,但其核心含义和使用场景有所不同。 #### 生命周期函数 生命周期函数是指框架或库在特定对象(如组件、指令、实例等)的创建、运行和销毁过程中自动调用的一组预定义函数。这些函数用于在不同的阶段执行相应的逻辑操作,例如初始化数据、绑定事件、更新状态或释放资源等。 以 Vue 组件为例,生命周期函数涵盖了从组件创建到挂载、更新再到卸载的全过程。常见的生命周期函数包括: - `beforeCreate`:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 - `created`:在实例创建完成后被调用,此时数据观测已经完成,但 DOM 还未生成。 - `beforeMount`:在挂载开始之前被调用,相关的 render 函数首次被调用。 - `mounted`:在挂载完成后被调用,此时可以访问和操作 DOM。 - `beforeUpdate`:在数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 - `updated`:在数据更新后调用,此时 DOM 已经更新以反映最新的数据。 - `beforeUnmount`:在卸载组件实例之前调用。 - `unmounted`:在卸载组件实例后调用,所有事件监听器都会被移除,所有的子组件也会被卸载。 生命周期函数的作用范围通常是整个组件实例,适用于处理组件的整体行为和状态管理[^1]。 #### 钩子函数 钩子函数是一个更广泛的概念,通常指在某个流程或生命周期中插入自定义逻辑的机制。它可以应用于多种上下文,包括但不限于组件、指令、路由、插件等。钩子函数的本质是在特定节点触发用户定义的行为。 以 Vue 的自定义指令为例,钩子函数用于响应与 DOM 元素相关的操作,例如设置样式、注册事件监听器等。常见的钩子函数包括: - `beforeMount`:在元素插入到 DOM 之前调用。 - `mounted`:在元素插入到 DOM 后调用,此时可以安全地操作 DOM。 - `beforeUpdate`:在组件更新前调用,适用于在更新前获取旧值。 - `updated`:在组件更新后调用,适用于需要对更新后的 DOM 进行操作的情况。 - `beforeUnmount`:在元素卸载前调用,适用于清理资源。 - `unmounted`:在元素卸载后调用,适用于执行最终的清理工作。 钩子函数的作用范围通常是单个 DOM 元素,适用于需要直接操作 DOM 的场景[^3]。 #### 区别总结 尽管两者都被称为“函数”并且都用于在特定阶段插入逻辑,但它们的核心区别在于: 1. **作用范围**: - 生命周期函数作用于整个组件实例,关注组件的整体状态变化。 - 钩子函数作用于特定的元素或模块,关注局部的操作和行为。 2. **应用场景**: - 生命周期函数常用于组件的数据初始化、状态管理和资源释放,例如在 `created` 钩子中发起网络请求,在 `mounted` 钩子中进行 DOM 初始化操作。 - 钩子函数常用于需要直接操作 DOM 的场景,例如实现输入框自动聚焦、拖拽功能、滚动监听等。 3. **触发时机**: - 生命周期函数的触发时机与组件的状态变化密切相关,涵盖组件从创建到销毁的全过程。 - 钩子函数的触发时机则取决于具体的模块或元素,例如在 Vue 指令中,钩子函数会在元素的渲染和更新过程中被调用。 4. **扩展性**: - 生命周期函数是框架预定义的,开发者只能在其提供的生命周期节点上添加逻辑。 - 钩子函数则具有更高的灵活性,开发者可以根据需求自定义钩子逻辑,例如通过自定义指令或插件扩展框架的功能。 #### 示例代码 以下是一个简单的 Vue 自定义指令示例,展示了如何利用钩子函数实现输入框自动聚焦的功能: ```vue <template> <input v-focus type="text" /> </template> <script> export default { directives: { focus: { mounted(el) { el.focus(); } } } }; </script> ``` 在这个例子中,`focus` 是一个局部自定义指令,它在 `mounted` 钩子中调用了 `el.focus()` 方法,使得输入框在页面加载完成后自动获得焦点。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值