コンテンツへスキップ

アニメーション

CSSキーフレーム、ネイティブVueトランジション、またはお好みのJavaScriptアニメーションライブラリを使用して、Radixプリミティブをアニメーション化します。

Radixプリミティブへのアニメーションの追加は、他のコンポーネントと似たように感じるはずですが、JSアニメーションライブラリを使用した終了アニメーションに関しては、ここでいくつかの注意点があります。

CSSアニメーションによるアニメーション

プリミティブをアニメーション化する最も簡単な方法はCSSを使用することです。

CSSアニメーションを使用して、マウントフェーズとアンマウントフェーズの両方をアニメーション化できます。後者は、Radixプリミティブがアニメーションの再生中にアンマウントを一時停止するため可能です。

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トランジションによるアニメーション

CSSアニメーションを使用する以外に、ネイティブのVue <Transition>を使用することを好むかもしれません。朗報です!コンポーネント(forceMountプロパティを持つ)をラップするだけで、完了です!

vue
<script setup lang="ts">
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'radix-vue'
</script>

<template>
  <DialogRoot v-model:open="open">
    <DialogTrigger>
      Edit profile
    </DialogTrigger>
    <DialogPortal>
      <Transition name="fade">
        <DialogOverlay />
      </Transition>
      <Transition name="fade">
        <DialogContent>
          <h1>Hello from inside the Dialog!</h1>
          <DialogClose>Close</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>

ヒント

さらに、Web Animations APIベースのアニメーションライブラリであるMotion Oneは、Radix Vueと完全に連携することがわかりました。

このStackblitzデモをチェックしてください🤩

JavaScriptアニメーションのためのアンマウントの委任

多くのステートフルプリミティブがビューから非表示になると、実際にはDOMから削除されます。JavaScriptアニメーションライブラリはアンマウントフェーズを制御する必要があるため、多くコンポーネントにforceMountプロパティを提供して、コンシューマーがこれらのライブラリによって決定されたアニメーションの状態に基づいて子要素のマウントとアンマウントを委任できるようにします。

たとえば、@vueuse/motionを使用してDialogをアニメーション化する場合は、コンポーザブルの1つ(useSpringなど)からのアニメーションの状態に基づいて、ダイアログのOverlayContentの部分を条件付きでレンダリングします。

vue
<script setup lang="ts">
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'radix-vue'
import { reactive, ref, watch } from 'vue'
import { useSpring } from '@vueuse/motion'

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>
      Edit profile
    </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>Hello from inside the Dialog!</h1>
        <DialogClose>Close</DialogClose>
      </DialogContent>
    </DialogPortal>
  </DialogRoot>
</template>

ヒント

このStackblitzデモをチェックしてください