使用ツアー
ステップを横断して単一のポップオーバーを再固定することで、ガイド付きツアーを構築するための構成。
使用法
自動インポートされたuseTourコンポーザーを使用して、ステップ間でアンカーが移動する単一のPopoverを使用してガイド付きツアーを実行します。コンポーザーはステップ状態を所有し、各ステップのtargetを<UPopover>にバインドするreferenceに解決しますが、コンテンツとナビゲーションは完全に制御できます。
Dashboard
Overview of your workspace.
Profile
Manage your account.
Settings
Configure your preferences.
<script setup lang="ts">
const dashboard = useTemplateRef('dashboard')
const profile = useTemplateRef('profile')
const settings = useTemplateRef('settings')
const tour = useTour([
{
target: () => dashboard.value,
title: 'Welcome aboard',
body: 'The popover re-anchors to each target as you step through the tour.'
},
{
target: () => profile.value,
title: 'Make it yours',
body: 'You own the content and the buttons — no extra theme or locale to maintain.',
side: 'right' as const
},
{
target: () => settings.value,
title: 'You\'re all set',
body: 'Press Finish to close the tour.'
}
])
</script>
<template>
<div class="w-full space-y-4">
<div class="flex justify-end">
<UButton icon="i-lucide-wand-sparkles" @click="tour.start()">
Start tour
</UButton>
</div>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div ref="dashboard" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Dashboard
</p>
<p class="text-sm text-muted">
Overview of your workspace.
</p>
</div>
<div ref="profile" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Profile
</p>
<p class="text-sm text-muted">
Manage your account.
</p>
</div>
<div ref="settings" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Settings
</p>
<p class="text-sm text-muted">
Configure your preferences.
</p>
</div>
</div>
<UPopover
:open="tour.open.value"
:reference="tour.reference.value"
:content="{ side: tour.current.value?.side, sideOffset: 8 }"
:dismissible="false"
arrow
>
<template #content>
<div class="p-4 max-w-xs space-y-2">
<div class="flex items-center justify-between gap-4">
<p class="font-semibold text-highlighted">
{{ tour.current.value?.title }}
</p>
<span class="text-xs text-muted tabular-nums">
{{ tour.index.value + 1 }} / {{ tour.total.value }}
</span>
</div>
<p class="text-sm text-muted">
{{ tour.current.value?.body }}
</p>
<div class="flex items-center justify-between pt-2">
<UButton
color="neutral"
variant="outline"
size="sm"
:disabled="!tour.hasPrev.value"
@click="tour.prev()"
>
Back
</UButton>
<UButton size="sm" @click="tour.next()">
{{ tour.hasNext.value ? 'Next' : 'Finish' }}
</UButton>
</div>
</div>
</template>
</UPopover>
</div>
</template>
<script setup lang="ts">
import { useTemplateRef } from 'vue'
const dashboard = useTemplateRef('dashboard')
const profile = useTemplateRef('profile')
const settings = useTemplateRef('settings')
const tour = useTour([
{
target: () => dashboard.value,
title: 'Welcome aboard',
body: 'The popover re-anchors to each target as you step through the tour.'
},
{
target: () => profile.value,
title: 'Make it yours',
body: 'You own the content and the buttons — no extra theme or locale to maintain.',
side: 'right' as const
},
{
target: () => settings.value,
title: 'You\'re all set',
body: 'Press Finish to close the tour.'
}
])
</script>
<template>
<div class="w-full space-y-4">
<div class="flex justify-end">
<UButton icon="i-lucide-wand-sparkles" @click="tour.start()">
Start tour
</UButton>
</div>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div ref="dashboard" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Dashboard
</p>
<p class="text-sm text-muted">
Overview of your workspace.
</p>
</div>
<div ref="profile" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Profile
</p>
<p class="text-sm text-muted">
Manage your account.
</p>
</div>
<div ref="settings" class="p-4 rounded-lg border border-default bg-elevated/50">
<p class="font-medium text-highlighted">
Settings
</p>
<p class="text-sm text-muted">
Configure your preferences.
</p>
</div>
</div>
<UPopover
:open="tour.open.value"
:reference="tour.reference.value"
:content="{ side: tour.current.value?.side, sideOffset: 8 }"
:dismissible="false"
arrow
>
<template #content>
<div class="p-4 max-w-xs space-y-2">
<div class="flex items-center justify-between gap-4">
<p class="font-semibold text-highlighted">
{{ tour.current.value?.title }}
</p>
<span class="text-xs text-muted tabular-nums">
{{ tour.index.value + 1 }} / {{ tour.total.value }}
</span>
</div>
<p class="text-sm text-muted">
{{ tour.current.value?.body }}
</p>
<div class="flex items-center justify-between pt-2">
<UButton
color="neutral"
variant="outline"
size="sm"
:disabled="!tour.hasPrev.value"
@click="tour.prev()"
>
Back
</UButton>
<UButton size="sm" @click="tour.next()">
{{ tour.hasNext.value ? 'Next' : 'Finish' }}
</UButton>
</div>
</div>
</template>
</UPopover>
</div>
</template>
各ステップには、ポップオーバーがアンカーするtargetが必要です。CSSセレクタ、要素、仮想要素(getBoundingClientRectを持つもの)、またはそれらのいずれかを返すref/ゲッターを受け入れます。nullを渡してステップをビューポートの中心に固定します。ステップ上の他のフィールド(title、body、side、...)はそのまま渡され、current経由で利用できます。
<script setup lang="ts">
const card = useTemplateRef('card')
const tour = useTour([
{ target: '#cta', title: 'Get started' },
{ target: () => card.value, title: 'Profile', side: 'right' },
{ target: null, title: 'All set' }
])
</script>
<template>
<UButton @click="tour.start()">Start tour</UButton>
<UPopover :open="tour.open.value" :reference="tour.reference.value" :dismissible="false">
<template #content>
<!-- your content + buttons -->
<UButton :disabled="!tour.hasPrev.value" @click="tour.prev()">Back</UButton>
<UButton @click="tour.next()">{{ tour.hasNext.value ? 'Next' : 'Finish' }}</UButton>
</template>
</UPopover>
</template>
- ポップオーバーのリアクティブ
referenceプロパティ上に構築されているため、アクティブなステップが変更されたときにポップオーバーがスムーズに再配置されます。 - ステップがアクティブになると、アクティブなターゲットが自動的にビューにスクロールされます。
- コンテンツを自分でレンダリングするので、メンテナンスする追加のテーマやロケールはありません。
API
useTour(steps, options?)
パラメータ
steps
MaybeRefOrGetter<TourStep[]> required
ツアーステップのリスト。静的配列、
ref、またはリアクティブステップのゲッターです。target
MaybeRefOrGetter<string | ReferenceElement | null | undefined>
ステップがアンカーされる要素。CSSセレクター
'#id''.class'、または#idとして解決された裸のID、要素、仮想要素、またはそれを返すref/getterを受け付けます。ビューポートでステップを中心にするにはnullを使用します。[key: string]
any
追加のフィールド
titlebodysideはcurrent経由で渡されます。options
UseTourOptions
ツアーの設定オプション。
initialStep
number
ツアーが始まるステップインデックス。
loop
boolean
最後のステップの後に最初のステップにループします。
scrollIntoView
boolean | ScrollIntoViewOptions
ステップがアクティブになるとターゲットをスクロールします。
戻る
open
Ref<boolean>
ツアーは現在開いているかどうか。
index
Ref<number>
ステップ範囲にクランプされた現在のステップインデックス。
current
ComputedRef<TourStep | undefined>
現在のステップオブジェクト、またはステップがない場合は
undefined。reference
ComputedRef<ReferenceElement | undefined>
<UPopover :reference>に渡す現在のステップの解決済みアンカー。total
ComputedRef<number>
ステップの合計数。
hasNext
ComputedRef<boolean>
次のステップが存在するかどうか。
hasPrev
ComputedRef<boolean>
前のステップが存在するかどうか。
start
(index?: number) => void
オプションで指定したインデックスでツアーを開きます。
next
() => void
次のステップに進みます。
loopオプションに応じてループまたは終了します。prev
() => void
前のステップに進みます。
goTo
(index: number) => void
特定のステップにジャンプしてツアーを開きます。
finish
() => void
ツアー終了。