Vue API リファレンス

@reelkit/vue のコンポーネント、コンポーザブル、ユーティリティの完全なリファレンスです。

Reel

タグ:<Reel>

Props

ReelProps

Prop型デフォルト説明
countnumber必須スライドの総数
direction'vertical' | 'horizontal''vertical'スクロールの方向
size[number, number] | undefinedundefined[幅, 高さ] の形での幅と高さ。省略すると ResizeObserver で自動計測します
initialIndexnumber0開始時のスライドのインデックス
loopbooleanfalse無限ループを有効にします
transitionTransitionTransformFnslideTransitionトランジション効果の関数。組み込み:slideTransition、fadeTransition、flipTransition、cubeTransition、zoomTransition
transitionDurationnumber300アニメーションの長さ(ms)
swipeDistanceFactornumber0.12スワイプのしきい値(0-1)
enableGesturesbooleantrueタッチやマウスのドラッグによる操作を有効にします
enableNavKeysbooleantrueキーボードの矢印キーによる操作を有効にします
enableWheelbooleanfalseマウスホイールでの操作を有効にします
wheelDebounceMsnumber200ホイールイベントのデバウンス(ms)
rangeExtractor(index: number, count: number) => number[]defaultRangeExtractor描画するインデックスを決める独自の関数
keyExtractor(index: number, indexInRange: number) => stringindex => index.toString()スライドの描画に使う独自のキー関数(ループ時に便利)
ariaLabelstringundefinedカルーセル領域のアクセシブルなラベル
reelStyleRecord<string, string | number>undefinedルートのコンテナー要素に適用するインラインスタイル
reelClassstring | Array | Objectundefinedルートのコンテナー要素に適用する CSS クラス
onNavKeyPress(increment: -1 | 1) => voidundefinedデフォルトの ArrowUp/ArrowDown の操作を置き換えるコールバックのプロップ。指定するとナビゲーションは自分で実装します(たとえば reelRef.value.next() を呼ぶ)。デフォルトの挙動にするなら省略してください。

イベント

イベントペイロード説明
beforeChange(index: number, nextIndex: number, indexInRange: number)スライドのトランジションが始まる前に発行されます
afterChange(index: number, indexInRange: number)スライドのトランジションが完了したあとに発行されます
slideDragStart(index: number)ドラッグジェスチャーが始まったときに発行されます
slideDragEnd(index: number)ドラッグジェスチャーが終わった(指を離した)ときに発行されます
slideDragCanceled(index: number)ドラッグジェスチャーがキャンセルされた(元に戻った)ときに発行されます
tap(event: GestureCommonEvent)シングルタップのジェスチャーで発行されます
doubleTap(event: GestureCommonEvent)ダブルタップのジェスチャーで発行されます
longPress(event: GestureCommonEvent)長押しのジェスチャーが始まったときに発行されます
longPressEnd(event: GestureEvent)長押しのジェスチャーが終わったときに発行されます

スロット

vue-html
<Reel :count="items.length">
  <template #item="{ index, indexInRange, size }">
    <!-- index       : number         — absolute slide index (0 to count-1) -->
    <!-- indexInRange : number         — position in the visible window (0, 1, or 2) -->
    <!-- size         : [number,number] — [width, height] of the container -->
    <MySlide :index="index" :size="size" />
  </template>

  <!-- default slot: overlay content rendered on top of the slides -->
  <ReelIndicator />
</Reel>
スロットスコープの props説明
#item{ index: number, indexInRange: number, size: [number, number] }表示中の各スライドを描画します。仮想化された範囲のインデックスごとに呼ばれます
defaultなしすべてのスライドの上に描画するオーバーレイの内容(インジケーター、コントロールなど)

ReelExpose

テンプレート参照を通じて公開される命令的な API:

vue
<script setup lang="ts">
import { ref } from 'vue';
import { Reel, type ReelExpose } from '@reelkit/vue';

const reelRef = ref<ReelExpose | null>(null);

function prev()  { reelRef.value?.prev(); }
function next()  { reelRef.value?.next(); }
function jump(i: number) { reelRef.value?.goTo(i, true); }
</script>

<template>
  <Reel ref="reelRef" :count="100">
    <template #item="{ index }">
      <div>Slide {{ index }}</div>
    </template>
  </Reel>
</template>
メソッド型説明
next()() => void次のスライドへ移動します
prev()() => void前のスライドへ移動します
goTo(index, animate?)(number, boolean?) => Promise<void>指定したスライドのインデックスへ移動します
adjust()() => voidスライドの位置を計算し直します(レイアウトが変わったあとに便利)
observe()() => voidジェスチャー、キーボード、ホイールのイベントの監視を始めます
unobserve()() => voidジェスチャー、キーボード、ホイールのイベントの監視を止めます

ReelIndicator

タグ:<ReelIndicator>

Props

ReelIndicatorProps

Prop型デフォルト説明
countnumber | undefined自動アイテムの総数。Reel の中に置けば親のコンテキストから自動で接続されます。単独で使うときは明示的に渡してください
activenumber | undefined自動現在アクティブなインデックス。Reel の中に置けば親のコンテキストから自動で接続されます。単独で使うときは明示的に渡してください
direction'vertical' | 'horizontal''vertical'インジケーターの向き
radiusnumber3ドットの半径(ピクセル)
visiblenumber5同時に通常サイズで表示するドットの最大数
gapnumber4ドットの間隔(ピクセル)
activeColorstring'#fff'アクティブなドットの色
inactiveColorstring'rgba(255, 255, 255, 0.5)'非アクティブなドットの色
edgeScalenumber0.5はみ出した端のドットの縮小率
onDotClick(index: number) => voidundefined独自のクリックハンドラー。Reel の中で省略すると、クリックしたドットのインデックスへ移動します
indicatorClassstring | Array | Objectundefinedtablist のルート要素に適用する CSS クラス
indicatorStyleCSSPropertiesundefinedtablist のルート要素にマージするインラインスタイル

イベント

イベントペイロード説明
dotClick(index: number)ドットがクリックされたときに発行され、ドットのインデックスを渡します

SwipeToClose

タグ:<SwipeToClose> — デフォルトスロットを、スワイプで閉じられるタッチ対応のコンテナーで包みます。

Props

SwipeToCloseProps

Prop型デフォルト説明
direction'up' | 'down'必須閉じるスワイプの方向。ギャラリーを閉じるなら "up"、ストーリーを閉じるなら "down" を使います
enabledbooleantrueスワイプで閉じるジェスチャーが有効かどうか
thresholdnumber0.2閉じるのに必要な、ビューポートの高さに対する割合(0-1)

イベント

イベントペイロード説明
close()スワイプがしきい値を超え、閉じるアニメーションが終わったときに発行されます

スロット

スロット説明
defaultスワイプで閉じるジェスチャーで包む内容

Observe

タグ: <Observe :signals="[…]"> — いずれかのシグナルが変わったとき、既定のスロットだけを描き直し、周りには手を触れません。

レンダー関数やテンプレートで core のシグナルを読んでも、それだけでは購読になりません。ふつうは toVueRef を使いますが、これは呼び出したコンポーネントにシグナルを結び付けるため、よく変わるシグナルではそのコンポーネント全体が描き直されます。Observe はより狭い境界です。値を見せている部分だけを包めば、残りはそのまま動きません。ストーリープレイヤーがヘッダーとプログレスバーを更新しつつ、どちらのスライダーも描き直さずに済ませているのがこの仕組みです。

Prop型説明
signalsreadonly Subscribable[]追いかけるシグナル。別の組を渡すと購読が張り替わり、同じ組ならそのまま保たれます。アンマウント時にはすべて解放されます。

プロパティの型は ObserveProps として公開されています。

vue
<script setup lang="ts">
import { Observe, createTimerController, toVueRef } from '@reelkit/vue';

const timer = createTimerController({ duration: 5000 });

// toVueRef binds the signal to THIS component: every tick re-renders all of
// it. Fine for a small component, wasteful when something heavy sits beside
// the part that changes.
const progress = toVueRef(timer.progress);
</script>

<template>
  <section>
    <!-- Only the slot below re-renders on a tick; the list keeps its DOM. -->
    <Observe :signals="[timer.progress]">
      <progress :value="timer.progress.value" max="1" />
    </Observe>

    <ExpensiveList :items="items" />

    <!-- The same value through toVueRef, for comparison. -->
    <p>{{ Math.round(progress * 100) }}%</p>
  </section>
</template>

コンポーネント全体がシグナルを追うなら toVueRef、その一部だけなら Observe を選んでください。

SoundProvider

タグ:<SoundProvider> — SoundController のインスタンスを作り、RK_SOUND_KEY を通じて子孫に提供するコンテキストプロバイダーです。デフォルトスロットをそのまま描画します。

vue
<template>
  <SoundProvider>
    <Reel :count="items.length">
      <template #item="{ index }">
        <VideoSlide :index="index" />
      </template>
      <MuteButton />
    </Reel>
  </SoundProvider>
</template>

RK_REEL_KEY と useReelContext

<Reel> が子孫に提供する InjectionKey<ReelContextValue> です。<ReelIndicator> の自動接続に内部で使われています。スライダーのコンテキストが必要な独自のコンポーネントでは useReelContext() を使ってください。

vue
<script setup lang="ts">
import { useReelContext } from '@reelkit/vue';

const ctx = useReelContext();

function jump(index: number) {
  ctx?.goTo(index, true);
}
</script>
プロパティ型説明
indexSignal<number>現在のスライドのリアクティブなインデックス
countSignal<number>アイテムの総数のリアクティブな値
goTo(index: number, animate?: boolean) => Promise<void>プログラムからスライドへ移動します

コンポーザブル

useBodyLock

渡した値が true のとき、ドキュメントの body のスクロールを止めます。参照カウントを使うので、同時に複数の呼び出し元がそれぞれ独立して止めたり解除したりできます。アンマウント時に自動で解除します。

typescript
import { ref } from 'vue';
import { useBodyLock } from '@reelkit/vue';

const isOpen = ref(false);
useBodyLock(isOpen);

// Also accepts a static boolean
useBodyLock(true);
パラメーター型説明
lockedRef<boolean> | booleanbody のスクロールを止めるかどうか。リアクティブな ref でも固定の真偽値でも受け取ります

useFullscreen

UseFullscreenOptions → UseFullscreenReturn

ブラウザー間で動く Fullscreen API を扱うコンポーザブルです。アンマウント時に自動でフルスクリーンを終了します。

typescript
import { ref } from 'vue';
import { useFullscreen } from '@reelkit/vue';

const containerRef = ref<HTMLElement | null>(null);
const { isFullscreen, request, exit, toggle } = useFullscreen({
  elementRef: containerRef,
});
戻り値型説明
isFullscreenSignal<boolean>現在のフルスクリーンの状態を反映するコアのシグナル(.value を読みます)
request() => Promise<void>参照した要素でフルスクリーンを要求します。別の要素がすでにフルスクリーンなら、先にそれを終了します(完了を待ちます)。
exit() => Promise<void>フルスクリーンを終了します
toggle() => Promise<void>フルスクリーンの状態を切り替えます

useSoundState

コンテキストから現在の SoundController にアクセスします。<SoundProvider> の中で呼ぶ必要があり、外で呼ぶと例外を投げます。

typescript
import { useSoundState } from '@reelkit/vue';

// Inside a SoundProvider descendant
const sound = useSoundState();

sound.muted;    // Signal<boolean>
sound.toggle(); // Toggle muted state

useOverlayUrlState

OverlayUrlStateOptions

オーバーレイ用の URL 状態コントローラーを作ります。それを <LightboxUrlOverlay> の :controller プロップに渡します。

手順と例は Vue ガイドの URL の状態 を参照してください。

オプション型デフォルト説明
paramstring必須アクティブなスライドを持つクエリパラメーター(たとえば "photo")。
adapterUrlAdapterHistory API読み書きに使うナビゲーションの仕組み。ルーターを使うアプリでは、ルーター自身の位置情報が古くならないよう、ルーターに連動したアダプターを渡してください。
codec{ decode(raw) => Id | null; encode(id) => string }必須通信形式:パラメーターの文字列 ↔ 安定した識別子で、コレクションは見ません。同じ Id を共有する対として locator と一緒に使います。デフォルトの ?photo=3 のインデックスギャラリーなら ...urlIndexKey(() => props.images.length) を展開し、ギャラリーが並べ替えられてもブックマークが保たれるようにするなら独自のもの(base64、スラッグ)を用意します。
locator{ locate(id) => number | null; locateAsync?(id) => Promise<number | null>; identify(index) => id }必須識別子を位置に対応させ、その妥当性を自分で判断します:locate(同期)、locateAsync(ページングされたギャラリー向けの非同期フォールバック)、identify(書き込み)。単純なインデックスのギャラリーなら ...urlIndexKey(() => props.images.length) を展開します。この locator と対応する codec を提供し、?photo=3 を現在の件数で制限するので、古い ?photo=99 は指されていないスライドを開く代わりに URL から取り除かれます。Vue の setup は一度しか実行されず、取り込んだ長さはページングされたフィードが伸びると古くなるので、数値ではなく getter を渡してください。ページングされたフィードや識別子で指すギャラリーは、代わりに独自の codec と locator の対を用意します。

useVueRouterUrlAdapter

Vue Router に連動した UrlAdapter です。ルーターを使うアプリで useOverlayUrlState の adapter オプションに渡すと、ナビゲーションの信頼できる情報源がルーターだけに保たれます。ルーターの裏で history.pushState を書くと、その位置情報が古くなり、次のナビゲーションでパラメーターが消えます。書き込むのはクエリだけなので、パス、ハッシュ、?tag=a&tag=b のような繰り返しのキーはそのまま残ります。変更のたびに、ルーターが同じページで push したのか、replace したのか、履歴をたどったのかを報告するので、<router-link> から開いたギャラリーは 1 回戻るだけで閉じます。

独自のサブパスから提供されるので、ルーターを使わないアプリのバンドルに vue-router が入ることはありません。vue-router は任意の peer dependency で、4.1 以降が必要です。アダプターはルーターの state ナビゲーションオプションで所有の印を運びますが、古いリリースはこれを無視します。古いルーターでも壊れることはなく、閉じるときに履歴を戻る代わりに、その場でパラメーターをクリアするだけです。

typescript
import { useVueRouterUrlAdapter } from '@reelkit/vue/vue-router-url-adapter';

const adapter = useVueRouterUrlAdapter();
const photo = useOverlayUrlState({
  param: 'photo',
  adapter,
  ...urlIndexKey(() => props.images.length),
});

toVueRef

コアの Subscribable(@reelkit/core の任意の Signal)を、読み取り専用の Vue の Ref につなぎます。コアのシグナルの値で Vue の再描画を起こしたいときは、常にこれを使ってください。描画関数やテンプレートで signal.value を直接読んでも、それだけではリアクティブに なりません。

購読は onScopeDispose で自動的に破棄されるので、Vue の setup() か、エフェクトスコープを扱える別のコンテキストの中で呼ぶ必要があります。

typescript
import { defineComponent, h } from 'vue';
import { toVueRef, useSoundState } from '@reelkit/vue';

export const MuteIcon = defineComponent({
  setup() {
    const sound = useSoundState();
    const muted = toVueRef(sound.muted); // Readonly<Ref<boolean>>

    return () => h('span', muted.value ? '🔇' : '🔊');
  },
});

asGenericPropKeys

受け取るアイテムについてジェネリックなコンポーネントを作ります。ReelPlayerOverlay や StoriesOverlay と同じ仕組みです。Vue 3.3 は型パラメーター付きの setup 関数 defineComponent(<T>(props: Props<T>) => …, options) を受け付けますが、そのパラメーターが保たれるのは options.props が prop 名を列挙している場合だけです。props オブジェクトを渡すと Vue はオブジェクトから prop の型を読み戻すため、T が失われます。asGenericPropKeys は props オブジェクトをそのまま渡しつつ、型チェッカーには名前のリストとして見せます。T は親がバインドした値から推論され、既定値、バリデーション、boolean への変換は実行時にもそのまま働きます。

型引数には基底のアイテムを使った props の型を渡し、コンポーネントには Vue 3.3 以降が必要です。スロットとイベントは T を使えません。スロットのスコープを型付けするには、テンプレートで型注釈を付けてください。

typescript
import { defineComponent, h, type PropType } from 'vue';
import { asGenericPropKeys } from '@reelkit/vue';

interface Item {
  id: string;
}

interface FeedProps<T extends Item> {
  items: T[];
  loop?: boolean;
}

const feedProps = {
  items: { type: Array as PropType<Item[]>, required: true as const },
  loop: { type: Boolean, default: false },
};

export const Feed = defineComponent(
  <T extends Item = Item>(props: FeedProps<T>) =>
    () =>
      h('ul', props.items.map((item) => h('li', item.id))),
  { name: 'Feed', props: asGenericPropKeys<FeedProps<Item>>(feedProps) },
);

hasRenderedNodes

hasRenderedNodes(nodes) は、スロットの結果がページに何かを描画するかどうかを判定します。親がスロットを空にしたときに自分の描画に戻るコンポーネント向けで、オーバーレイもそうしています。false の v-if の後ろに中身があるスロットもコメントノードを返すので、配列の長さで判定すると埋まっているとみなしてフォールバックを捨ててしまいます。hasRenderedNodes はフラグメントを展開し、コメントノードを無視し、null や undefined には false を返します。分岐の判定には hasRenderedNodes(slots.controls?.(scope)) を使ってください。

アクセシビリティ

<Reel> は aria-roledescription="carousel" を持つ role="region" として描画されます。aria-label(TS でのプロップ名は ariaLabel)を渡すと、スクリーンリーダー向けの名前が付きます。控えめなライブリージョンが、スライドが変わるたびに「Slide N of M」と読み上げます。非アクティブなスライドには inert 属性が付くので、フォーカスや支援技術での移動では飛ばされます。

<ReelIndicator> は、ドットにローミング tabindex を持つ role="tablist" として描画されます。矢印キーでフォーカスが移動し、Enter か Space でスライドが有効になります。

<Reel> を囲む独自のモーダルを作るなら、フォーカスを戻したり閉じ込めたりするために captureFocusForReturn、createFocusTrap、getFocusableElements が @reelkit/vue から再エクスポートされています。

パッケージのエクスポート

@reelkit/vue の公開エクスポートの一覧:

typescript
// Components
import {
  Reel,
  ReelIndicator,
  SwipeToClose,
  SoundProvider,
  Observe,
} from '@reelkit/vue';

// Types
import type {
  ReelExpose,
  ReelContextValue,
  SwipeToCloseDirection,
  SwipeToCloseProps,
  UseFullscreenOptions,
  UseFullscreenReturn,
} from '@reelkit/vue';

// Context & composables
import {
  RK_REEL_KEY,
  useReelContext,
  RK_SOUND_KEY,
  useBodyLock,
  useFullscreen,
  useSoundState,
  toVueRef,
} from '@reelkit/vue';

// Generic components
import { asGenericPropKeys } from '@reelkit/vue';

// Utilities (re-exported from @reelkit/core)
import {
  createDefaultKeyExtractorForLoop,
  defaultRangeExtractor,
} from '@reelkit/vue';

// Core re-exports
import {
  // Signals & reactivity
  createSignal, createComputed, reaction, batch, createDeferred,

  // Transitions
  slideTransition, fadeTransition, flipTransition,
  cubeTransition, zoomTransition, getSlideProgress,

  // Content loading & preloading
  createContentLoadingController, createContentPreloader,
  observeMediaLoading,

  // Sound
  createSoundController, syncMutedToVideo,

  // Fullscreen
  fullscreenSignal, requestFullscreen, exitFullscreen,

  // DOM & cleanup
  observeDomEvent, createDisposableList, createBodyLock, sharedBodyLock,

  // Size detection
  observeElementSize, getViewportSize, observeViewportSize,
  isMobileWidth, fitAspectRatio, isTouchDevice,

  // Autoplay & download
  createTimerController, createSlideshowController, downloadFile,

  // Focus management
  captureFocusForReturn, createFocusTrap, getFocusableElements,

  // Gestures
  createGestureController,

  // Video
  captureFrame, createSharedVideo,

  // Animation
  animate,

  // Utilities
  noop, clamp, abs, first, last, extractRange,
  lerp, isNegative, generate,
} from '@reelkit/vue';