• 06 【生命周期 模板引用】


    11.生命周期

    vue2

    image-20220629211626515

    vue3

    lifecycle_2

    • Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
      • beforeDestroy改名为 beforeUnmount
      • destroyed改名为 unmounted
    • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
      • beforeCreate===>setup()
      • created=======>setup()
        在setup比beforeCreate还先执行
      • beforeMount ===>onBeforeMount
      • mounted=======>onMounted
      • beforeUpdate===>onBeforeUpdate
      • updated =======>onUpdated
      • beforeUnmount ==>onBeforeUnmount
      • unmounted =====>onUnmounted

    关于两个销毁生命周期,可以在组件实例上用v-if打成

    所有罗列在下面的 API 都应该在组件的 setup() 阶段被同步调用。相关细节请看指南 - 生命周期钩子

    11.1 onBeforeMount#

    注册一个钩子,在组件被挂载之前被调用。

    • 类型

      function onBeforeMount(callback: () => void): void
      
      • 1
    • 详细信息

      当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。

      这个钩子在服务器端渲染期间不会被调用。

    11.2 onMounted#

    注册一个回调函数,在组件挂载完成后执行。

    • 类型

      function onMounted(callback: () => void): void
      
      • 1
    • 详细信息

      组件在以下情况下被视为已挂载:

      • 其所有同步子组件都已经被挂载 (不包含异步组件或 树内的组件)。
      • 其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。

      这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端执行。

      这个钩子在服务器端渲染期间不会被调用。

    • 示例

      通过模板引用访问一个元素:

      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

    11.3 onBeforeUpdate#

    注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。

    • 类型

      function onBeforeUpdate(callback: () => void): void
      
      • 1
    • 详细信息

      这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。

      这个钩子在服务器端渲染期间不会被调用。

    11.4 onUpdated#

    注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。

    • 类型

      function onUpdated(callback: () => void): void
      
      • 1
    • 详细信息

      父组件的更新钩子将在其子组件的更新钩子之后调用。

      这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的。如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。

      这个钩子在服务器端渲染期间不会被调用。

      警告

      不要在 updated 钩子中更改组件的状态,这可能会导致无限的更新循环!

    • 示例

      访问更新后的 DOM

      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    11.5 onBeforeUnmount#

    注册一个钩子,在组件实例被卸载之前调用。

    • 类型

      function onBeforeUnmount(callback: () => void): void
      
      • 1
    • 详细信息

      当这个钩子被调用时,组件实例依然还保有全部的功能。

      这个钩子在服务器端渲染期间不会被调用。

    11.6 onUnmounted#

    注册一个回调函数,在组件实例被卸载之后调用。

    • 类型

      function onUnmounted(callback: () => void): void
      
      • 1
    • 详细信息

      一个组件在以下情况下被视为已卸载:

      • 其所有子组件都已经被卸载。
      • 所有相关的响应式作用 (渲染作用以及 setup() 时创建的计算属性和侦听器) 都已经停止。

      可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。

      这个钩子在服务器端渲染期间不会被调用。

    • 示例

      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    11.7 onErrorCaptured#

    注册一个钩子,在捕获了后代组件传递的错误时调用。

    • 类型

      function onErrorCaptured(callback: ErrorCapturedHook): void
      
      type ErrorCapturedHook = (
        err: unknown,
        instance: ComponentPublicInstance | null,
        info: string
      ) => boolean | void
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 详细信息

      错误可以从以下几个来源中捕获:

      • 组件渲染
      • 事件处理器
      • 生命周期钩子
      • setup() 函数
      • 侦听器
      • 自定义指令钩子
      • 过渡钩子

      这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串。

      你可以在 errorCaptured() 中更改组件状态来为用户显示一个错误状态。注意不要让错误状态再次渲染导致本次错误的内容,否则组件会陷入无限循环。

      这个钩子可以通过返回 false 来阻止错误继续向上传递。请看下方的传递细节介绍。

      错误传递规则

      • 默认情况下,所有的错误都会被发送到应用级的 app.config.errorHandler (前提是这个函数已经定义),这样这些错误都能在一个统一的地方报告给分析服务。
      • 如果组件的继承链或组件链上存在多个 errorCaptured 钩子,对于同一个错误,这些钩子会被按从底至上的顺序一一调用。这个过程被称为“向上传递”,类似于原生 DOM 事件的冒泡机制。
      • 如果 errorCaptured 钩子本身抛出了一个错误,那么这个错误和原来捕获到的错误都将被发送到 app.config.errorHandler
      • errorCaptured 钩子可以通过返回 false 来阻止错误继续向上传递。即表示“这个错误已经被处理了,应当被忽略”,它将阻止其他的 errorCaptured 钩子或 app.config.errorHandler 因这个错误而被调用。

    11.8 onActivated#

    注册一个回调函数,若组件实例是 `` 缓存树的一部分,当组件被插入到 DOM 中时调用。

    这个钩子在服务器端渲染期间不会被调用。

    11.9 onDeactivated#

    注册一个回调函数,若组件实例是 KeepAlive 缓存树的一部分,当组件从 DOM 中被移除时调用。

    这个钩子在服务器端渲染期间不会被调用。

    11.10 汇总

    • this的数据:除了beforeCreate,其他12个生命周期的 this 都能获得组件实例对应初始化完成的内容。
    • beforeUpdate() 永远只在所有父子组件的 mounted() 之后才会触发!
    • 例子里的生命周期根据功能进行了划分,生命周期的顺序都标了数字!
    • setup() 调用时间,与调用时间相关功能的讲解。onMounted之类的生命周期函数必须同步调用!onXxxxx()就不讲解了,在对应的选项API生命周期名的函数之前执行。
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    image-20220810151058920

    父组件的前4个声明周期执行完后,开始执行子组件的前7个生命周期,执行完毕后,再接着开始执行父组件的mounted()生命周期。

    12.模板引用

    虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref attribute:

    
    
    • 1

    ref 是一个特殊的 attribute,和 v-for 章节中提到的 key 类似。它允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用。这可能很有用,比如说在组件挂载时将焦点设置到一个 input 元素上,或在一个元素上初始化一个第三方库。

    12.1 访问模板引用

    为了通过组合式 API 获得该模板 ref,我们需要声明一个同名的 ref:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果不使用

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    注意,你只可以在组件挂载后才能访问 ref。如果你想在模板中的表达式上访问 input,在初次渲染时会是 null。这是因为在初次渲染前这个元素还压根不存在呢!

    12.2v-for 中的模板引用#

    需要 v3.2.25 及以上版本

    当在 v-for 中使用模板引用时,对应的 ref 中包含的值是一个数组,它将在元素被挂载后包含对应整个列表的所有元素:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在演练场中尝试一下

    应该注意的是,ref 数组并不保证与源数组相同的顺序。

    12.3 函数模板引用

    除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。该函数会收到元素引用作为其第一个参数:

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null。你当然也可以绑定一个组件方法而不是内联函数。

    配置v-for

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    12.4 组件上的 ref

    模板引用也可以被用在一个子组件上。这种情况下引用中获得的值的是组件实例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果一个子组件使用的是选项式 API 或没有使用

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number } (ref 都会自动解包,和一般的实例一样)。

    TypeScript 用户请参考:为组件的模板引用标注类型

    12.5 defineExpose详解

    vue3新特性,如果是options api类型的组件,不声明 expose 时,默认暴露当前组件实例的全部内容,声明了 expose 选项, expose 数组内标记的才会暴露。(expose:[]则什么都不暴露,注意这个问题。也可以利用这个特性提高组件使用的规范。)

    export default defineComponent({
      expose:['nameA',...],// 可以 expose 当前实例的任何内容
      methods:{
        nameA(){}
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6