VUE3浅析---指令以及生命周期

VUE3的内置指令用法实例以及生命周期函数的使用和原理探索



一、内置指令

1、v-text:更新元素的文本内容

const text = "这是测试v-text"
<h1 v-text="text"></h1>

2、v-html:更新元素的文本内容,并且是可以识别html标签的

const html = "<span style='color:red;'>这是测试v-html</span>"
<h1 v-html="html"></h1>

3、v-bind:绑定某一个属性,简写为:

  const id = "123"
  const  flag = true
  const style = {color: "green"}
  
  <h1 :id="id">这是v-bind绑定id</h1>
  <h1 class="c" :class="['a','b']">这是v-bind绑定class,测试动态增加class</h1>
  <h1 :class="[flag ? 'a' : 'b']">这是v-bind绑定class,测试表达式</h1>
  <h1 :style="style">这是v-bind绑定style</h1>
  
	<style>
		.a { color:red; }
		.b{ font-size: smaller; }
		.c { font-family: 'Times New Roman', Times, serif; }
	</style>

4、v-once:只会渲染一次元素

h1标签加了v-once之后,无论按钮点击多少下,值始终为0,不会改变。v-once的使用场景为:当多次触发某些操作时,又不想频繁更新某一个组件时,就可以使用v-once来限制对应的组件。

   import { ref } from 'vue'
   let count = ref<number>(0)
	const once = () => {
	  count.value++;
	  console.log(count.value)
	}
  
  <button @click="once" style="height: 100px; width: 100px; background: green;"></button>
  <div>
   <h1 v-text="count" v-once></h1> 
  </div>

5、v-memo:一般配置v-for来使用,使用场景和v-once一样,可以灵活定义限制条件,当v-memo不传值时,作用和v-once一样。

v-memo的作用场景和v-once的使用场景相似,但是比v-once更加灵活,v-memo可以通过自定义限制条件,通过条件是否满足,进而来处理组件。以下场景:当点击了按钮之后,clicked的值变成了0,并且同时我们改变了第一条数据和第二条数据的值,但是发现,渲染的时候只改变了第一条数据。而第二条数据并没有发生变化,这就说明,v-memo中条件成立的数据才会被重新渲染。

import { ref, reactive } from 'vue'
const clicked = ref(1)
const list = reactive([
    { id: 0, name: "000" },
    { id: 1, name: "111" },
    { id: 2, name: "222" },
    { id: 3, name: "333" },
]);
const memo = () => {
    clicked.value = 0;
    list[0].name = "1"; //修改结果 1
    list[2].name = "2"; // 修改结果 2
};
<button @click="memo" style="height: 100px; width: 100px; background: green">memo</button>
<div v-for="(item, index) in list" v-memo="[index == clicked]" :key="index">
	<p>index: {{ item }} - selected: {{ clicked }}</p>
</div>

5、v-for:循环,一般在使用的时候,要指定一个key,指定key作用于后续的diff算法有关系

<div v-for="(item, index) in list" :key="index">
	<p> {{ item }} </p>
</div>

6、v-on:监听绑定事件,也可以简写为@

用来绑定事件,可以是一个方法名,也可以是一个表达式。对于普通函数的调用,还可以通过以下修饰符来处理自定义事件,比如使用.stop来阻止组件的事件触发。

  • .stop:阻止父组件事件的触发。也就是只执行自己的函数事件。
  • .{keyAlias} :只在某些按键下触发处理函数。
  • .prevent:阻止表单默认事件,会阻止form当中的action行为
<button v-on:click="change" style="width: 100px; height: 30px; background: green">改变值</button>
<button @click="change" style="width: 100px; height: 30px; background: green">改变值</button>

// .once只会让事件触发一次
<button @click.once="change" style="width: 100px; height: 30px; background: green">改变值</button>

// .stop会阻止parent事件的触发
  <div @click="parent">
    <p>{{ message }}</p>
    <button @click.stop="change1" style="width: 100px; height: 30px; background: green">改变值</button>
  </div>

// .prevent阻止跳转到https://www.baidu.com
  <form action="https://www.baidu.com">
    <button @click.prevent="change2" style="width: 100px; height: 30px; background: green">
      改变值
    </button>
  </form>

import { ref } from 'vue'

const message = ref('This is a page about stuff')
const change = () => {
  console.log('change被点击了')
  message.value = 'Hello Vue 3!'
}

const change2 = () => {
  console.log('change2被点击了')
  message.value = 'Hello Vue 3!'
}

动态事件:

<button v-on:[event]="change" style="width: 100px; height: 30px; background: green">改变值</button>
<button @[event]="change" style="width: 100px; height: 30px; background: green">改变值</button>

7、v-model:绑定模型,将数据绑定某一个组件上。

<input v-model="message" />

import { ref } from 'vue'
const message = ref('This is a page about stuff')

8、v-pre:将标签里的文本按照Vue的模版语法显示,常见是就是显示{{}}

<span v-pre>{{ const a = 1; const b = 2; }}</span>

9、v-show:显示或者隐藏组件

v-show的原理是在组件上增加display样式属性,来达到显示或者隐藏组件的目的。频繁的操作显示隐藏的场景时,使用v-show性能更好。

<button @click="isShow = !isShow" style="width: 100px; height: 30px; background: green">显示隐藏</button>
<span v-show="isShow">显示了</span>

const isShow = ref(true)

10、v-if:显示或者隐藏

v-if的原理是通过创建或者销毁组件,来达到显示或者隐藏组件的目的,一般用在组件在第一次加载的场景时,使用v-if性能更好。

<button @click="isShow = !isShow" style="width: 100px; height: 30px; background: green">显示隐藏</button>
<span v-if="isShow">显示了</span>

const isShow = ref(true)

11、v-solt:插槽

vue中的插槽使得组件设计更加灵活,可以在组件中使用插槽设计灵活的满足组件上动态的化的展示。

11.1、匿名插槽

当我们直接使用<solt></solt>定义插槽的时候,此时的插槽称为匿名插槽。也就是说没有名字的插槽,实际上VUE会这个插槽默认设置一个default的名字。

// SoltComponetents.vue
<template>
    <div class="header">
        <slot>这是子组件header内容</slot>
    </div>
</template>

<script setup lang="ts"></script>
<style></style>

// PComponents.vue
<template>
    <SoltComponetents>
        <template #default></template>
    </SoltComponetents>
</template>

<script setup lang="ts">
import SoltComponetents from '../solt/SoltComponetents.vue'
</script>

<style>
.header {
  background: turquoise;
  width: 100px;
  height: 100px;
}
.main {
  background: rgb(226, 148, 92);
  width: 100px;
  height: 100px;
}
.bottom {
  background: rgb(43, 31, 204);
  width: 100px;
  height: 100px;
}
</style>
11.2、具名插槽

当我们直接使用<solt name="main"></solt>定义插槽的时候,此时的插槽称为具名插槽。也就是说给插槽起了个名字叫做main。父组件在使用插槽的时候,使用<template #main></template>使名称为main的插槽生效,其中#mainv-solt:main的缩写。

// SoltComponetents.vue
<template>
    <div class="main">
        <slot name="main">这是子组件main内容</slot>
    </div>
</template>

<script setup lang="ts"></script>
<style></style>

// PComponents.vue
<template>
    <SoltComponetents>
        <template #main></template> 
    </SoltComponetents>
</template>

<script setup lang="ts">
import SoltComponetents from '../solt/SoltComponetents.vue'
</script>

<style>
.header {
  background: turquoise;
  width: 100px;
  height: 100px;
}
.main {
  background: rgb(226, 148, 92);
  width: 100px;
  height: 100px;
}
.bottom {
  background: rgb(43, 31, 204);
  width: 100px;
  height: 100px;
}
</style>
11.3、作用域插槽(插槽传值)

当我们直接使用<solt name="bottom"></solt>定义插槽的时候,可以在插槽内定义数据,并将数据传递到父组件使用

// SoltComponetents.vue
<template>
    <div class="bottom">
        <slot name="bottom" :data="data" :count="count">{{ pData }}</slot>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const data = ref('这是子组件定义的数据')
const count = ref(100)
</script>

<style></style>

// PComponents.vue
<template>
    <SlotComponetents>
        // <template #bottom="pros"> {{ pros.data }} -- {{ pros.count }} </template> // 如果参数比较多,接受的时候直接使用对象接受,比如使用pros接受,使用pros.count获取对象中count属性的值
        // 如果参数比较少,接受的时候直接使用ES6的{}进行解构接受,这样看起来比较直观
        <template #bottom="{ data, count }"> {{ data }} -- {{ count }} </template> 
    </SlotComponetents>
</template>

<script setup lang="ts">
import SlotComponetents from '../slot/SlotComponetents.vue'
</script>

<style>
.header {
  background: turquoise;
  width: 100px;
  height: 100px;
}
.main {
  background: rgb(226, 148, 92);
  width: 100px;
  height: 100px;
}
.bottom {
  background: rgb(43, 31, 204);
  width: 100px;
  height: 100px;
}
</style>

11.4、动态插槽名

动态插槽就是动态的设置插槽的名称,以达到动态设置插槽的目的,实际项目中经常使用,这里不做介绍。

注意:

  • 在父组件中使用插槽的时候,如果直接使用插槽组件,那么插槽组件中定义的多个插槽都可以被展示,一旦在父组件中的插槽组件中加入<template v-solt></template>或者<template></template>标签,那么匿名插槽将不会展示。
  • 在父组件中使用插槽的时候,在父组件中的插槽组件中加入<template #default></template>标签或者一旦指定了任意插槽的名字,即使当前指定的插槽的名称不是匿名插槽的名字,匿名插槽也会被展示。

二、自定义指令

<script setup> 中,任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令。

1、案例:自定义一个按钮权限控制自定义指令。
<script setup lang="ts">
// 导入自定义指令类型
import type { Directive } from 'vue'

// 模拟后台返回的当前用户当前页面的按钮权限数据
const btnPromiss = { btnPromiss: 'edit,add' }
// const btnPromiss = { btnPromiss: 'all' }

// 自定义按钮权限逻辑
const vBtnPromiss: Directive<HTMLElement, string> = (el, bingding) => {
  if (btnPromiss.btnPromiss == 'all') {
    return
  }
  if (btnPromiss.btnPromiss.indexOf(bingding.value) < 0) {
    el.style.display = 'none' // 如果按钮权限组数据中没有当前设置的按钮权限时,设置当前按钮权限不显示
  }
}

// 给自定指令绑定动态参数
//const dBtn = ref('test')
const dBtn = ref({
    name: "a",
    age: "12",
});
</script>

<template>
    <div>
        --------------------
        <button v-btn-promiss="'delete'">删除</button>
        <button v-btn-promiss="'add'">增加</button>
        <button v-btn-promiss="'edit'">编辑</button>
	    // 自定义指令也可以绑定动态参数,然后在bingding.arg中接收
	    <button v-btn-promiss:btn.boo="'edit'">编辑</button>
		<button v-btn-promiss:[dBtn].boo="'edit'">编辑</button>
    </div>
</template>

<style scoped lang="css">
button {
  margin: 5px;
}
</style>

2、案例:自定义指标,图片懒加载
<script setup lang="ts">
import { type Directive, ref } from 'vue'

/**
 * import.meta.glob: 使用glob加载静态资源,实际上就是懒加载,形式上和以下方式是等价的,模块加载器,资源的加载需要你真正的调用对应的函数才会加载它
 * let imagesMudoles = { 'headImagesMudoles': () => import '', 'footerImagesMudoles': () => import ''}
 *
 * import.meta.globEager:使用globEager加载静态资源,模块加载器,资源已经真正加载好了,直接使用即可。该函数已经被弃用,可使用glob函数中增加{ eager: true }代替。
 * let imagesMudoles = { 'headImagesMudoles': () => import '', 'footerImagesMudoles': () => import ''}
 */
const imagesList: Record<string, { default: string }> = import.meta.glob(
    "../assets/images/*.*",
    {
        eager: true,
    }
);

// const imagesList1: Record<string, { default: string }> = import.meta.globEager(
//   '../assets/images/*.*'
// )
// console.log('imagesList1', imagesList1)

// 加图片地址解析出来
const images = Object.values(imagesList).map((image) => image.default);

// 默认展示图片
import defImage from "../assets/def.jpg";
// 自定义图片懒加载指令
const vLazyImage: Directive<HTMLImageElement, string> = (el, bingding) => {
    el.src = defImage;
    // IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。构造函数的返回值是一个观察器实例。
    // 实例的observe方法可以指定观察哪个 DOM 节点,如果需要观察多个DOM节点可以多次添加observe方法。里面提供了多个可是不同类型的DOM操作,如上面的方法。
    /**
   * callback函数的参数(entries)是一个数组,每个成员都是一个IntersectionObserverEntry对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员,
    每个IntersectionObserverEntry对象属性含义如下:
      boundingClientRect:目标元素的矩形区域的信息
      intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
      intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
      rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
      isIntersecting:目标元素是否与视口(或根元素)交叉
      isVisible:并未查阅到相关资料,且经过测试其并不会发生变化
      target:被观察的目标元素,是一个 DOM 节点对象
      time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
   */
    const observer = new IntersectionObserver((intersectionObserver) => {
        console.log("intersectionObserver", intersectionObserver);
        if (intersectionObserver[0].intersectionRatio > 0) {
            setTimeout(() => {
                el.src = bingding.value; // 当前区域可视时,将真正图像显示到页面上
                observer.unobserve(el); // 取消监听
            }, 2000);
        }
    });

    observer.observe(el); // 监听
};

</script>

<template>
    <div>
        <hr />

        <div>
            <img
                style="width: 375px; height: 667px"
                v-for="(image, index) in images"
                v-lazy-image="image"
                :key="index"
            />
        </div>
    </div>
</template>

<style scoped lang="css">
button {
  margin: 5px;
}
</style>

三、生命周期

1、生命周期钩子介绍:

VUE3 setup语法糖模式下,主要有以下几个生命周期函数。

  • onBeforeMount:页面加载完成前执行这个生命周期函数,此时不可以获取操作DOM
  • onMounted:页面加载完成后执行这个生命周期函数,此时可以获取操作DOM
  • onBeforeUpdate:在改变变量的值之前执行这个生命周期函数
  • onUpdated:在改变变量的值之后执行这个生命周期函数
  • onBeforeUnmount:页面加载销毁前执行这个生命周期函数,此时可以获取操作DOM
  • onUnmounted:页面加载销毁后执行这个生命周期函数,此时不可以获取操作DOM
  • onActivated:使用<keep-alive></keep-alive>缓存组件时,当组件被加载后会执行这个函数
  • onDeactivated:使用<keep-alive></keep-alive>缓存组件时,当组件被销毁后会执行这个函数
// // PComponents.vue
<template>
    <button
        @click="show = !show"
        style="width: 80px; height: 40px; background: green"
    >
        删除组件
    </button>
    <keep-alive>
        <SlotComponetents v-if="show">
            <template #bottom="pro">
                {{ pro.data }} -- {{ pro.count }}
            </template>
        </SlotComponetents>
    </keep-alive>
</template>

<script setup lang="ts">
import SlotComponetents from '../slot/SlotComponetents.vue'
import { ref } from 'vue'
const show = ref(true)
</script>

<style>
.header {
  background: turquoise;
  width: 600px;
  height: 100px;
}
.main {
  background: rgb(226, 148, 92);
  width: 600px;
  height: 100px;
}
.bottom {
  background: rgb(43, 31, 204);
  width: 600px;
  height: 100px;
}
</style>

// SoltComponetents.vue
<template>
    <div class="bottom" ref="mainDiv">
        <slot name="bottom" :data="data" :count="count"></slot>
        <button
            @click="add"
            style="width: 80px; height: 40px; background: green"
        >1
        </button>
    </div>
</template>

<script setup lang="ts">
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onActivated,
  onDeactivated
} from 'vue'

const data = ref('这是子组件定义的数据')
const count = ref(100)

const mainDiv = ref<HTMLElement>()

const add = () => {
  count.value = count.value + 1
}

// 页面加载完成前执行这个生命周期函数,此时不可以获取操作DOM
onBeforeMount(() => console.log('before mount', '获取DOM:', mainDiv.value))

// 页面加载完成后执行这个生命周期函数,此时可以获取操作DOM
onMounted(() => console.log('mounted', '获取DOM:', mainDiv.value))

// 在改变变量的值之前执行这个生命周期函数
onBeforeUpdate(() => console.log('before update', '获取DOM:', mainDiv.value?.innerHTML))

// 在改变变量的值之后执行这个生命周期函数
onUpdated(() => console.log('updated', '获取DOM:', mainDiv.value?.innerHTML))

// 页面加载销毁前执行这个生命周期函数,此时可以获取操作DOM
onBeforeUnmount(() => console.log('before unmount', '获取DOM:', mainDiv.value))

// 页面加载销毁后执行这个生命周期函数,此时不可以获取操作DOM
onUnmounted(() => console.log('unmounted', '获取DOM:', mainDiv.value))

// 使用<keep-alive></keep-alive>缓存组件时,当组件被加载后会执行这个函数
onActivated(() => console.log('active', '获取DOM:', mainDiv.value?.innerHTML))

// 使用<keep-alive></keep-alive>缓存组件时,当组件被销毁后会执行这个函数
onDeactivated(() => console.log('inactive', '获取DOM:', mainDiv.value?.innerHTML))
</script>

<style></style>

2、源码解读:
2.1、注册生命周期函数:

VUE3的生命周期函数的定义在apiLifecycle.ts这个文件中定义的,在这个文件中,通过一下方式导出了常用的生命周期函数,每一个生命周期函数都调用了createHook这个函数,参数实际上是各个生命周期函数的缩写。

export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT)
export const onMounted = createHook(LifecycleHooks.MOUNTED)
export const onBeforeUpdate = createHook(LifecycleHooks.BEFORE_UPDATE)
export const onUpdated = createHook(LifecycleHooks.UPDATED)
export const onBeforeUnmount = createHook(LifecycleHooks.BEFORE_UNMOUNT)
export const onUnmounted = createHook(LifecycleHooks.UNMOUNTED)
export const onServerPrefetch = createHook(LifecycleHooks.SERVER_PREFETCH)
2.2、createHook函数实际上会调用injectHookinjectHook中有一个特殊的参数target代表的是当前组件的实例currentInstance,而之后,所有的生命周期函数都会被注册到当前实例currentInstance上:
// 主要是将生命周期函数挂载到当前实例上,以便于后期渲染页面时调用
export function injectHook(
    type: LifecycleHooks,
    hook: Function & { __weh?: Function },
    target: ComponentInternalInstance | null = currentInstance,
    prepend: boolean = false
): Function | undefined {
    if (target) {
	    // 先从当前实例上获取生命周期函数,如果没有那就初始化为一个空的数组
        const hooks = target[type] || (target[type] = []);
        // cache the error handling wrapper for injected hooks so the same hook
        // can be properly deduped by the scheduler. "__weh" stands for "with error
        // handling".
        const wrappedHook =
            hook.__weh ||
            (hook.__weh = (...args: unknown[]) => {
			    // 如果当前实例被销毁了,那就不用注册了,直接返回,相当于做了一个缓存
                if (target.isUnmounted) {
                    return;
                }
                // disable tracking inside all lifecycle hooks
                // since they can potentially be called inside effects.
                // 这里先取消依赖收集,防止重复收集依赖,因为在组件初始化的时候,就已经进行过依赖收集了。
                pauseTracking();
                // Set currentInstance during hook invocation.
                // This assumes the hook does not synchronously trigger other hooks, which
                // can only be false when the user does something really funky.
                // 将target设置为当前实例
                setCurrentInstance(target);
                // 并且执行相应的生命周期函数
                const res = callWithAsyncErrorHandling(
                    hook,
                    target,
                    type,
                    args
                );
                // 释放当前实例
                unsetCurrentInstance();
                // 恢复依赖收集
                resetTracking();
                return res;
            });
        if (prepend) {
            hooks.unshift(wrappedHook);
        } else {
            hooks.push(wrappedHook);
        }
        return wrappedHook;
    } else if (__DEV__) {
        const apiName = toHandlerKey(
            ErrorTypeStrings[type].replace(/ hook$/, "")
        );
        warn(
            `${apiName} is called when there is no active component instance to be ` +
                `associated with. ` +
                `Lifecycle injection APIs can only be used during execution of setup().` +
                (__FEATURE_SUSPENSE__
                    ? ` If you are using async setup(), make sure to register lifecycle ` +
                      `hooks before the first await statement.`
                    : ``)
        );
    }
}

2.3、调用生命周期函数:

生命周期函数的调用在renderer.ts中,componentUpdateFn函数中会进行函数的调用

const componentUpdateFn = () => {
	// 先判断下当前组件是不是已经挂载了
    if (!instance.isMounted) {
        let vnodeHook: VNodeHook | null | undefined;
        const { el, props } = initialVNode;
        const { bm, m, parent } = instance;
        const isAsyncWrapperVNode = isAsyncWrapper(initialVNode);

        toggleRecurse(instance, false);
        // beforeMount hook
        // bm就是beforeMount钩子的缩写,如果当前实例上有bm,则先执行bm
        if (bm) {
            invokeArrayFns(bm);
        }
        
	    // ………………省略部分源码………………

        if (el && hydrateNode) {
            // vnode has adopted host node - perform hydration instead of mount.
           // ………………省略部分源码………………
           
        // 此时还没有DOM的化,执行下边的逻辑之后,就会将DOM挂载到VNode上,之后就存在DOM了,执行mounted操作就可以操作DOM了。
        } else {
            if (__DEV__) {
                startMeasure(instance, `render`);
            }
            const subTree = (instance.subTree = renderComponentRoot(instance));
            if (__DEV__) {
                endMeasure(instance, `render`);
            }
            if (__DEV__) {
                startMeasure(instance, `patch`);
            }
            // 将VNode装载到容器当中,此后就会有DOM
            patch(
                null,
                subTree,
                container,
                anchor,
                instance,
                parentSuspense,
                isSVG
            );
            if (__DEV__) {
                endMeasure(instance, `patch`);
            }
            initialVNode.el = subTree.el; // 挂载DOM
        }
        // mounted hook
        // m就是mounted的缩写,这里执行onMounted生命周期函数
        if (m) {
            queuePostRenderEffect(m, parentSuspense);
        }
	    // ………………省略部分源码………………
    } else {

		// ………………省略部分源码………………

        // beforeUpdate hook
        // bu就是beforeUpdate的缩写,这里开始执行onBeforeUpdate生命周期函数
        if (bu) {
            invokeArrayFns(bu);
        }
        // onVnodeBeforeUpdate
        if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
            invokeVNodeHook(vnodeHook, parent, next, vnode);
        }
        
        // ………………省略部分源码………………
        
        // updated hook
        // u就是updated,这里开始执行onUpdated生命周期函数
        if (u) {
            queuePostRenderEffect(u, parentSuspense);
        }

		// ………………省略部分源码………………
        
    }
};

// unmount进行组件卸载,这里调用unmountComponent函数清空收集的所有依赖
const unmount: UnmountFn = (
    vnode,
    parentComponent,
    parentSuspense,
    doRemove = false,
    optimized = false
) => {
	// ………………省略部分源码………………
	
	// 清空收集的所有依赖
    unmountComponent(vnode.component!, parentSuspense, doRemove)

	// 清空所有的依赖之后,就会执行onBeforeUnmount生命周期函数
	if (shouldInvokeDirs) {
	    invokeDirectiveHook(vnode, null, parentComponent, "beforeUnmount");
	}

    // 接着还会调用该函数删除DOM下边的所有子树
	unmountChildren(dynamicChildren, parentComponent, parentSuspense, false, true);

	// 最后执行onUnmounted函数,此时表明组件已经卸载完成
	invokeDirectiveHook(vnode, null, parentComponent, 'unmounted')
    
    // ………………省略部分源码………………
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue 3中,`keep-alive`组件具有两个新增的生命周期钩子函数:`activated`和`deactivated`。当组件被缓存并重新激活时,`activated`函数会被调用;当组件被缓存并离开时,`deactivated`函数会被调用。这两个钩子函数允许我们在组件被缓存和激活/离开时执行相应的逻辑操作。除了新增的生命周期钩子函数,`keep-alive`组件仍然会遵循普通的Vue组件的生命周期顺序,例如`created`、`mounted`、`updated`和`destroyed`等。所以在使用`keep-alive`组件时,可以根据需要在这些生命周期函数中进行相应的操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Vue生命周期(keep-alive缓存特殊activated(组件激活时)、deactivated(组件停用时))、父子组件的执行顺序](https://blog.csdn.net/muzidigbig/article/details/112696398)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Vue缓存路由(keep-alive)以及新的生命周期](https://blog.csdn.net/code_dream_wq/article/details/128713825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜间沐水人

文章编写不易,一分钱也是爱。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值