动画
使用 CSS 关键帧动画、原生 Vue Transition 或您选择的 JavaScript 动画库为 Reka UI 添加动画效果。
为 Reka UI 添加动画的感觉应与其他组件类似,但这里需要注意关于使用 JS 动画库实现退出动画的一些注意事项。
使用 CSS 动画实现动画效果
为 Primitives 添加动画的最简单方式是使用 CSS。
您可以使用 CSS 动画来为挂载和卸载阶段添加动画。后者之所以可行,是因为 Reka UI 会在动画播放期间暂停卸载。
css
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.DialogOverlay[data-state="open"],
.DialogContent[data-state="open"] {
animation: fadeIn 300ms ease-out;
}
.DialogOverlay[data-state="closed"],
.DialogContent[data-state="closed"] {
animation: fadeOut 300ms ease-in;
}使用 Vue Transition 实现动画
除了使用 CSS 动画,您可能更倾向于使用原生的 Vue <Transition>。好消息是!只需将组件(具有 forceMount 属性)包裹起来,就完成了!
vue
<script setup lang="ts">
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'reka-ui'
</script>
<template>
<DialogRoot v-model:open="open">
<DialogTrigger>
编辑个人资料
</DialogTrigger>
<DialogPortal>
<Transition name="fade">
<DialogOverlay />
</Transition>
<Transition name="fade">
<DialogContent>
<h1>来自对话框内部的问候!</h1>
<DialogClose>关闭</DialogClose>
</DialogContent>
</Transition>
</DialogPortal>
</DialogRoot>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>⭐️ 使用 Motion Vue 实现动画
Motion Vue 是 Reka UI 推荐的动画库。这个轻量级且功能强大的库能与组件无缝集成,并为创建流畅、高性能的动画提供了极大的灵活性。
vue
<script setup lang="ts">
import { AnimatePresence, Motion } from 'motion-v'
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'reka-ui'
</script>
<template>
<DialogRoot>
<DialogTrigger>
编辑个人资料
</DialogTrigger>
<DialogPortal>
<AnimatePresence multiple>
<DialogOverlay as-child>
<Motion
:initial="{ opacity: 0, scale: 0 }"
:animate="{ opacity: 1, scale: 1 }"
:exit="{ opacity: 0, scale: 0.6 }"
/>
</DialogOverlay>
<DialogContent as-child>
<Motion
:initial="{ opacity: 0, top: '0%' }"
:animate="{ opacity: 1, top: '50%' }"
:exit="{ opacity: 0, top: '30%' }"
>
<h1>来自对话框内部的问候!</h1>
<DialogClose>关闭</DialogClose>
</Motion>
</DialogContent>
</AnimatePresence>
</DialogPortal>
</DialogRoot>
</template>tip
查看这个 Stackblitz 演示 🤩
为 JavaScript 动画委托卸载过程
当许多有状态的 Primitives 从视图中隐藏时,它们实际上会从 DOM 中移除。JavaScript 动画库需要控制卸载阶段,因此我们在许多组件上提供了 forceMount 属性,允许使用者根据这些库确定的动画状态来委托子组件的挂载和卸载。
例如,如果您想使用 @vueuse/motion 为 Dialog 添加动画,您可以根据其某个组合式函数(如 useSpring)提供的动画状态,有条件地渲染对话框的 Overlay 和 Content 部分:
vue
<script setup lang="ts">
import { useSpring } from '@vueuse/motion'
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'reka-ui'
import { reactive, ref, watch } from 'vue'
const stages = {
initial: { opacity: 0, scale: 0, top: 0, },
enter: { opacity: 1, scale: 1, top: 50, },
leave: { opacity: 0, scale: 0.6, top: 30, },
}
const styles = reactive(stages.initial)
const { set } = useSpring(styles, {
damping: 8,
stiffness: 200,
})
const open = ref(false)
watch(open, () => {
if (open.value)
set(stages.enter)
else
set(stages.leave)
})
</script>
<template>
<DialogRoot v-model:open="open">
<DialogTrigger>
编辑个人资料
</DialogTrigger>
<DialogPortal v-if="styles.opacity !== 0">
<DialogOverlay
force-mount
:style="{
opacity: styles.opacity,
transform: `scale(${styles.scale})`,
}"
/>
<DialogContent
force-mount
:style="{
opacity: styles.opacity,
top: `${styles.top}%`,
}"
>
<h1>来自对话框内部的问候!</h1>
<DialogClose>关闭</DialogClose>
</DialogContent>
</DialogPortal>
</DialogRoot>
</template>tip
查看这个 Stackblitz 演示
