重学vue3-内置组件

276 阅读3分钟

Transition && TransitionGroup

动画组件

触发条件:

  • v-if
  • v-show
  • component 切换的动态组件
  • 改变特殊的key

css过渡class

image.png

  • v-enter-from 进入动画的起始状态
  • v-enter-active 用来定义进入动画的持续时间、延迟与速度曲线类型
  • v-enter-to 进入动画的结束状态
  • v-leave-from 离开动画的起始状态
  • v-leave-active 用来定义离开动画的持续时间、延迟与速度曲线类型。
  • v-leave-to 离开动画的结束状态

为过渡效果命名 name=xxx,name也可以是一个变量,实现动态过渡

<Transition name="slide-fade">
  <p v-if="show">hello</p>
</Transition>

/*
  进入和离开动画可以使用不同
  持续时间和速度曲线。
*/
.slide-fade-enter-active {
  transition: all 0.3s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

与css原生动画一起使用

<Transition name="bounce">
  <p v-if="show" style="text-align: center;">
    Hello here is some bouncy text!
  </p>
</Transition>

.bounce-enter-active {
  animation: bounce-in 0.5s;
}
.bounce-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}

自定义过渡class,比如在使用Animate.css插件库的时候

  • enter-from-class
  • enter-active-class
  • enter-to-class
  • leave-from-class
  • leave-active-class
  • leave-to-class
<!-- 假设你已经在页面中引入了 Animate.css -->
<Transition
  name="custom-classes"
  enter-active-class="animate__animated animate__tada"
  leave-active-class="animate__animated animate__bounceOutRight"
>
  <p v-if="show">hello</p>
</Transition>

可复用过渡效果

<!-- MyTransition.vue -->
<script>
// JavaScript 钩子逻辑...
</script>

<template>
  <!-- 包装内置的 Transition 组件 -->
  <Transition
    name="my-transition"
    @enter="onEnter"
    @leave="onLeave">
    <slot></slot> <!-- 向内传递插槽内容 -->
  </Transition>
</template>

<style>
/*
  必要的 CSS...
  注意:避免在这里使用 <style scoped>
  因为那不会应用到插槽内容上
*/
</style>

使用
<MyTransition>
  <div v-if="show">Hello</div>
</MyTransition>

某个节点初次渲染时应用一个过渡效果,添加appear属性

<Transition appear>
  ...
</Transition>

元素间过渡 && 过渡模式

因为进入和离开的元素是在同时开始动画的,所以一般都用 position:absolute 来避免二者同时存在出现布局问题;

如果想要先执行离开动画,在其完成后再执行元素的进入动画可以给Transtion 添加 mode=out-in

<Transition mode="out-in">
  <button v-if="docState === 'saved'">Edit</button>
  <button v-else-if="docState === 'edited'">Save</button>
  <button v-else-if="docState === 'editing'">Cancel</button>
</Transition>

组件间过渡

<Transition name="fade" mode="out-in">
  <component :is="activeComponent"></component>
</Transition>

js动画钩子

<Transition
  @before-enter="onBeforeEnter"
  @enter="onEnter"
  @after-enter="onAfterEnter"
  @enter-cancelled="onEnterCancelled"
  @before-leave="onBeforeLeave"
  @leave="onLeave"
  @after-leave="onAfterLeave"
  @leave-cancelled="onLeaveCancelled"
>
  <!-- ... -->
</Transition>

关于动画性能

transform和opacity属性制作动画非常高效,height和margin这种则会触发布局变动,耗费较高

TransitionGroup 用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。

//class 会被应用在列表内的元素上,而不是容器元素上。
<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</TransitionGroup>
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
  position: absolute;
}

KeepAlive

KeepAlive 用来缓存被移除的组件实例,默认会缓存内部的所有组件实例

它会根据组件的 name 选项进行匹配

注:<script setup> 的单文件组件会自动根据文件名生成对应的 name 选项

  • include 包含组件
  • exclude 不包含组件
<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>

也可以和router-view一起使用

<router-view v-slot="{ Component }">
    //max设置最大缓存实例
    <keep-alive :max="10" include="helloWord,helloVue">
        <component :is="Component" />
    </keep-alive>
</router-view>

缓存实例的生命周期

被keepAlive缓存的组件被移除时变为不活跃状态onDeactivated(),重新插入到DOM树时变为被激活 onActivated()

  • onActivated 在组件挂载时也会调用,并且 onDeactivated 在组件卸载时也会调用。
  • 这两个钩子不仅适用于 <KeepAlive> 缓存的根组件,也适用于缓存树中的后代组件。

Teleport

将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

常见的例子就是在一个组件内部创建一个全屏的模态框的时候,逻辑写在同一个组件内,

	<button @click="open = true">Open Modal</button>
        //传入动态的disabled 来处理是行内组件还是浮层
	<Teleport to="body" :disabled="isMobile">
		<div v-if="open" class="modal">
			<p>Hello from the modal!</p>
			<button @click="open = false">Close</button>
		</div>
	</Teleport>

disabledtrue的时候 就变成行内组件

image.png