#100-项目
[[vue-use]] [[utils]]
🗓️ 创建日期: [[2022-11-01#19:54]]
注:官方也有个组件transition
也可以实现过度,但我感觉用得不是很自由所以写了个函数,可以非常自由的进行过度,比如v-if在父亲的父亲的父亲上,但是其下的任意组件都能自由的设置动画,众所周知,这只是一个函数,也十分简单,这也是一种思想,将需要的功能抽象出来,未来哪天发现要用,就不需要从新想了
export function useIfAnimationState(
duration: MaybeRef<number> = 500,
active: MaybeRef<boolean> = false
) {
// 是否显示的核心状态信息
const _active = ref(active);
// 动画过度持续时间
const _duration = ref(duration);
// 是否正在过度
const transitioning = ref(false);
let timeout = null as any;
watch(_active, () => {
transitioning.value = true;
clearTimeout(timeout);
timeout = setTimeout(() => (transitioning.value = false), _duration.value);
});
// 动画进入显示状态,当v-if为true时,组件会开始渲染,但是,不会有过度,所以这个函数确保渲染前保持隐藏状态,然后再进入显示状态时,就会有动画了
const transitionActive = ref(false);
watchEffect(() => {
!_active.value
? (transitionActive.value = false)
: setTimeout(() => (transitionActive.value = true));
});
return {
show: () => (_active.value = true),
hidden: () => (_active.value = false),
active,
transitionActive,
safeActive: computed(() => _active.value || transitioning.value) // 确保动画完成后再隐藏元素,
transitioning,
duration: _duration,
};
}
在需要隐藏与显示动画的地方使用 transitionActive
const style = {transform: transitionActive ? `` : `translateX(-100%)`}
如果你的元素是全屏的,那么将会从屏幕的左边之外跑到屏幕里面,此代码要运行还需要[[#duration
的使用]]
const style = {transfromDuration:`${duration}px`}
<template>
<div v-if="safeActive"></div>
</template>
它的作用是,只要动画在运行,就不会隐藏,当动画执行完毕后,隐藏元素,这样动画就不会还没播放就被隐藏了
它代表动画正在运行
下面代码为上面这个组件的边框,当悬浮在图标上时,显示悬浮窗
如果你想看更多效果可以 网易云游戏静态页面
<script lang="ts" setup>
import { useIfTransition } from "@/utils/use";
const { dialogWidth = 258 } = defineProps<{ dialogWidth?: number }>();
const { transitionActive, safeActive, show, hidden, duration } =
useIfTransition(200);
</script>
<template>
<!-- <div @mouseenter="show"> -->
<div @mouseenter="show" @mouseleave="hidden">
<slot></slot>
<div
class="absolute top-[100%] right-0 h-0 w-full flex justify-center pb-2 transition origin-bottom-center"
:class="{
'scale-100 opacity-100': transitionActive,
'scale-0 opacity-0': !transitionActive,
}"
:style="{ transitionDuration: `${duration}ms` }"
v-if="$slots.dialog && safeActive"
>
<!-- 三角块 -->
<div
class="rotate-45 h-2 w-2 bg-brand-color flex-shrink-0 absolute top-[100%] left-[50%]"
:style="{
transform: `translate(-50%,-50%) rotate(45deg)`,
}"
></div>
<div
class="absolute top-[100%] right-0 flex flex-col bg-color1 rounded-md overflow-hidden w-[258px] max-h-[480px] min-h-[200px]"
:style="{ width: `${dialogWidth}px` }"
>
<!-- 顶步线条 -->
<div class="top-0 w-full h-1 flex-shrink-0 bg-brand-color"></div>
<!-- 内容区块 -->
<div class="overflow-y-auto"><slot name="dialog"></slot></div>
</div>
</div>
</div>
</template>