生命周期函数

@ Lifecycle Hooks
Overview
组件的一生:创建 → 挂载 → 更新 → 销毁;又细分为前、后两个阶段
开发者根据组件的状态在特定阶段执行特定的操作
基本使用:引入对应的包 → 执行函数 → 传入回调
更多 API,请访问 APILifecycle
Vue的生命周期函数
Lifetime
onBeforeMount()
注册一个钩子,在组件被挂载之前被调用
初始化;拉取/操作数据;但是 DOM还未就绪
import { onBeforeMount } from 'vue'

onBeforeMount(() => {
    console.log("onBeforeMount");
})
onMounted()
注册一个回调函数,在组件挂载完成后执行:DOM已就绪
多用于项目初始化
可以执行多个,但是仅仅执行1次
运维通过 追加 的方式,定义新的逻辑
import { onMounted } from 'vue'

onMounted(() => {
    console.log("onMounted:Initialization before");
})
onMounted(() => {
    console.log("onMounted:Initialization now");
})
onBeforeUpdate()
注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之前调用
onUpdated()
更新完毕
注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用
捕获响应式数据的更新;静态数据更新不会响应
onBeforeUnmount()
卸载之前
注册一个回调函数,在组件实例被卸载之前调用
是onBeforeUnmount,不是onBeforeUnmounted
onUnmounted()
注册一个回调函数,在组件实例被卸载之后调用
vue2中是destroy
onActivated()
适用于缓存组件
注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用
onDeactivated()
适用于缓存组件
注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用
[] 使用响应式数据配合事件、延时或浏览器地址栏,查看视图的生命周期函数执行情况
<template>
    <div class="about">
        <div>about</div>
        <div>{{ cd }}秒后返回/work</div>
    </div>
</template>
    
<script setup>
import { onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, ref } from 'vue';
import { useRouter } from 'vue-router';
    
const router = useRouter();
    
let cd = ref(5)
    
setInterval(() => {
    cd.value--;
    if (cd.value == -1) {
        router.replace('/work')
    }
}, 1000)
    
onMounted(() => {
    console.log('onMounted');
})
onBeforeUpdate(() => {
    console.log('onBeforeUpdate');
})
onUpdated(() => {
    console.log('onUpdated');
})
onBeforeUnmount(() => {
    console.log('onBeforeUnmount');
})
onUnmounted(() => {
    console.log('onUnmounted');
})
</script>
已安装 Vs Code 扩展 Vue Vscode Snippets 的,请注意编辑过程中的代码片段提示,不要一个一个字母编辑
Homework
[] 焦点管理:自定义搜索组件,单击时,显示并自动获取焦点
方案1:使用表单属性 autofocus
<input type="text" ref="ipt" placeholder="your name" autofocus>
方案2:使用 模板引用 获取元素
搜索组件 Search.vue
import { useTemplateRef, onMounted } from 'vue';
const sql = useTemplateRef('sql')
onMounted(() => {
    sql.value.focus()
})
<input type="text" ref="sql" placeholder="your keyword">
父组件 - 单击按钮显示搜索框
import { ref } from 'vue';
import Search from './components/Search.vue'
const isShow = ref(false)
<button @click="isShow = !isShow">click</button>
<Search v-if="isShow"></Search>
可以使用 v-show 吗?
模态框的显示隐藏和本案例有什么区别?
[] 页面滚动事件
方案1:固定定位的元素变换样式,如添加阴影
<header> 固定在顶部 fixed;当滚动超过一定距离后,为 <header> 指定阴影
页面加载时,绑定事件处理器 - 监听页面的滚动事件
页面卸载时,移除绑定的事件处理器;别要注意定时器的清除
1.1 使用 模板引用 实现
<header class="header" ref="header">header</header>
import { onMounted, onUnmounted, useTemplateRef } from 'vue'

const header = useTemplateRef('header')

const fn = () => {
  header.value.classList.toggle('fixed', window.scrollY > 1000)
}

onMounted(() => {
  window.addEventListener('scroll', fn)
})

onUnmounted(() => {
  window.removeEventListener('scroll', fn)
})
1.2 使用动态类实现
<header class="header" :class="{ 'shadow': isShow }">header</header>
const isShow = ref(false)

onMounted(() => {
  window.addEventListener('scroll', () => {
    isShow.value = window.scrollY > 300
  })
})

// ...
样式略
方案2:粘性定位的元素变换样式 - HomeView.vue 页面/视图滚动到某个位置时,粘性定位在顶部
利用 getBoundingClientRect() 获取元素相对视口的 top;当 top 为0时,表示粘性定位触发,应用特定样式
这里使用传统事件方式 - 建议使用事件侦听的方式
<div class="tab-box" ref="tab-box"></div>
import { onMounted, onUnmounted, useTemplateRef } from 'vue'

const tabBox = useTemplateRef('tab-box')

onMounted(() => {
  window.onscroll = function () {
    const rect = tabBox.value.getBoundingClientRect()
    if (rect.top <= 0) {
      tabBox.value.classList.add('sticky')
    } else {
      tabBox.value.classList.remove('sticky')
    }
  }
})

onUnmounted(() => {
  window.onscroll = null
})
使用事件监听 addEventListener() 和 样式的 toggle() 优化,如使用具名函数便于清除事件侦听
onMounted(() => {
  window.addEventListener('scroll', () => {
    let rect = tabBox.value.getBoundingClientRect()
    tabBox.value.classList.toggle('sticky', rect.top <= 0)
  })
})
[] 定位页面
页面加载完毕,在顶部呈现;页面跳转时,可能会保留之前的滚动位置
onMounted(() => {
  window.scrollTo(0, 0)
  // ...
})
多个页面需要控制时,可以使用 路由守卫 Guard
router.afterEach((to, from) => {
  document.title = to.meta.title;
  window.scrollTo(0, 0);
});
[] 标签页 - 使用 动态组件 切换时,查看各组件的生命周期函数执行情况