Skip to content

Instantly share code, notes, and snippets.

@mekefly
Last active November 1, 2022 13:10
Show Gist options
  • Save mekefly/7c4cadd3fea0939c54a5bb209ed26c79 to your computer and use it in GitHub Desktop.
Save mekefly/7c4cadd3fea0939c54a5bb209ed26c79 to your computer and use it in GitHub Desktop.
让v-if拥有动画过度(vue use).md

🧲 相关:

#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的使用

在需要隐藏与显示动画的地方使用 transitionActive

const style = {transform: transitionActive ? `` : `translateX(-100%)`}

如果你的元素是全屏的,那么将会从屏幕的左边之外跑到屏幕里面,此代码要运行还需要[[#duration的使用]]

duration的使用

const style = {transfromDuration:`${duration}px`}

safeActive的使用

<template>
<div v-if="safeActive"></div>
</template>

它的作用是,只要动画在运行,就不会隐藏,当动画执行完毕后,隐藏元素,这样动画就不会还没播放就被隐藏了

transitioning是什么

它代表动画正在运行

高级使用例子

下面代码为上面这个组件的边框,当悬浮在图标上时,显示悬浮窗

如果你想看更多效果可以 网易云游戏静态页面

<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment