跳转到内容

Tour 引导 ​

用于逐步介绍界面中的关键功能。

用法 ​

逐步介绍页面中的关键操作

组件结构 ​

加粗的是必需部件。

data-scope="tour":root · backdrop · spotlight · positioner · content · title · description · progress-text · progress-indicator · progress-dot · prev-trigger · next-trigger · skip-trigger · close-trigger · arrow

示例 ​

居中步骤 ​

用于引导的开场与结束

定位 ​

为每一步选择合适的浮层方向

无遮罩 ​

保留页面环境并突出目标

设计指引 ​

何时使用 ​

  • 首次进入复杂页面时介绍关键操作。
  • 新功能上线后提供一次性引导。

何时不用 ​

  • 界面结构本身不清晰时应先改进界面。
  • 需要随时查看的说明使用帮助内容或文字提示。

特性 ​

  • 聚光灯突出目标,spotlightPadding 控制留白。
  • 高亮框同步目标节点的实际圆角,直角与圆角目标保持各自轮廓。
  • autoScroll 自动将目标滚动到可见区域。
  • 无目标步骤在视口中居中,适合开场与结束。
  • showBackdrop=false 关闭背景暗幕,但保留目标高亮环。
  • 支持受控步序、完成和跳过回调。
  • 气泡走 M4 sheet 三件套(1px 描边、不透明底、投影),与对话框同源;边界由描边承担,不只靠影分层。锚定步从贴着目标的那条边涨开入场,退场按 exit 档收拢。
  • 末行三颗按钮与角落的关闭按钮走 Action Control 家族配方:下一步是整条引导的主线动作,显式 solid 品牌实心;上一步为中性描边,跳过为无壳 ghost;关闭按钮为 icon 档 ghost 面。悬停与按下沿画布承载阶梯换底并 0.97 缩放,Space / Enter 与触屏按住期间投影 data-pressed。
  • 标题为 heading-3,说明文字为 13px 说明档;说明区是气泡里唯一让步的滚动面,滚到头不带动页面。进度圆点是 8px 正圆,当前那颗拉成 20px 胶囊。

组合 ​

  • 使用 progress-text 或 progress-indicator 展示进度。
  • 使用 prev-trigger、next-trigger 与 skip-trigger 提供导航。

最佳实践 ​

  • 步数控制在三到五步。
  • 从第一步开始提供跳过入口。
  • 记录完成状态,避免重复展示。

反模式 ​

  • 不要强制用户完成引导。
  • 不要指向尚未渲染的目标。

API 参考 ​

产物 ​

层值
自定义元素<xh-tour>
Vue 组件XhTourArrow XhTourBackdrop XhTourCloseTrigger XhTourContent XhTourDescription XhTourNextTrigger XhTourPositioner XhTourPrevTrigger XhTourProgressDot XhTourProgressIndicator XhTourProgressText XhTourRoot XhTourSkipTrigger XhTourSpotlight XhTourTitle
组合式函数useTour
状态机tourMachine
皮肤@xihan-ui/styles/tour.css

Props ​

属性类型必填说明
stepsTourStep[]步骤清单。它同时是步序的上界与读屏「第 m 步,共 n 步」的分母。
valuenumber当前步序(0 起)。提供即受控:内部不再自行修改,只发 onValueChange。
defaultValuenumber非受控初值,默认 0。
openboolean
defaultOpenboolean
placementPlacement整份引导的首选放置位,默认 bottom;单步可用自己的 placement 覆盖。
dirDirection文字方向,默认 ltr。只改写浮层在行内轴上 start 与 end 的落点。
offsetnumber浮层与目标的间距(px)。
closeOnEscapeboolean
closeOnInteractOutsideboolean层外交互关闭,默认 false:引导需经 skip 或 close 两个明确出口退出。
showBackdropboolean绘制遮罩,默认 true。
spotlightPaddingnumber高亮框在目标四周留出的空白(px),默认 8。
autoScrollboolean展开与换步时自动把目标滚进视口(nearest,已可见时不动),默认 true。
translationsPartial<TourTranslations>
onValueChange(details: TourValueChangeDetails) => void步序变化意图回调;受控时是唯一出口,非受控时随内部写入一并通知。
onOpenChange(details: TourOpenChangeDetails) => voidopen 变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。
onComplete(details: TourCompleteDetails) => void末步再按下一步:先发它,再经 onOpenChange 关闭。
onSkip(details: TourSkipDetails) => void用户主动放弃(skip-trigger 或 Escape):先发它,再经 onOpenChange 关闭。

TourStep ​

steps 的元素。

字段类型必填说明
idstring是稳定标识,写入 data-step-id;作者据此对应(埋点、按步定制渲染)。
targetstring | null高亮目标的 CSS 选择器。null / 省略 / 查询不到节点都视为该步不锚定任何元素: 浮层居中、不绘制高亮框、不显示箭头。
titlestring
descriptionstring
placementPlacement该步的首选放置位;未提供时沿用整份引导的 placement。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
open-changeTourOpenChangeDetailsopen 状态变化;detail 为 { open: boolean }
value-changeTourValueChangeDetails步序变化;detail 为 { value: number }
completeTourCompleteDetails末步再按下一步;detail 为 { step: number }
skipTourSkipDetails用户放弃(跳过按钮或 Escape);detail 为 { step: number }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhTourRootdefaultTourRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhTourProgressDotindexnumber | string是圆点对应的步序,0 基;兼收字符串。
XhTourRootcontainer() => Element | null本实例三张 Tour 浮层的 Portal 容器;优先于应用级配置。
XhTourRootchildrenSlotChildren<TourRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
root'open' | 'closed'
backdrop'open' | 'closed'
spotlight'open' | 'closed'
positioner'open' | 'closed'
content'open' | 'closed'
prev-trigger'open' | 'closed'
next-trigger'open' | 'closed'
skip-trigger'open' | 'closed'

以下名称仅用于内部状态机。

状态:open · closed

事件:OPEN · CLOSE · VALUE.SET · STEP.PREV · STEP.NEXT · SKIP · GEOMETRY.SYNC · CONTROLLED.OPEN · CONTROLLED.CLOSE · PRESS.START · PRESS.END

判据:isOpenControlled · isLastStep · isLastStepOpenControlled · canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
openboolean
valuenumber当前步序,恒在 [0, count - 1] 内;清单为空时为 0。
countnumber
currentStepTourStep | null当前步的声明;清单为空时为 null。
firstStepboolean停在首步:上一步按钮据此禁用。
lastStepboolean停在末步:下一步按钮据此更换文案(完成)。
anchoredboolean该步锚定了页面元素:居中步为 false,此时不绘制高亮框也不显示箭头。
progressTextstring「第 m 步,共 n 步」。作者未编写 progress-text 的内容时由适配器填入。
setOpen(next: boolean) => void
setValue(next: number) => void直接跳到某一步;越界会被夹回 [0, count - 1]。
goToNextStep() => void末步再前进一步 = 完成:先发 onComplete,再关闭。
goToPrevStep() => void
skip() => void放弃引导:先发 onSkip,再关闭。
remeasure() => void重新测量高亮框与浮层位置:目标节点被外部改动(换位、变尺寸)后调用它校准。
getRootProps() => T['element']
getBackdropProps() => T['element']
getSpotlightProps() => T['element']
getPositionerProps() => T['element']
getContentProps() => T['element']
getTitleProps() => T['element']
getDescriptionProps() => T['element']
getProgressTextProps() => T['element']
getProgressIndicatorProps() => T['element']
getProgressDotProps(props: TourProgressDotProps) => T['element']
getPrevTriggerProps() => T['button']
getNextTriggerProps() => T['button']
getSkipTriggerProps() => T['button']
getCloseTriggerProps() => T['button']
getArrowProps() => T['element']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Spaceopen 且焦点在 content 上(不在按钮等控件上)走到下一步;停在末步时完成引导并关闭
Escapeopen 且 closeOnEscape放弃引导(发 onSkip)并关闭
ArrowUp / ArrowDown / ArrowLeft / ArrowRightopen一概不接管:既不换步也不阻止默认行为,留给页面滚动与读屏浏览
Tab / Shift+Tabopen焦点陷在 content 内循环,跑出去会被拉回来
Enter / Spaceheld in prev-trigger / next-trigger / skip-trigger / close-trigger按住期间该按钮投影 data-pressed,与指针 :active 同一副按压面;抬起、失焦或气泡收起撤下

ARIA ​

以下属性由 connect 生成。

部件属性值
backdroparia-hidden'true'
spotlightaria-hidden'true'
contentaria-describedbydescription 部件的 id
contentaria-hidden!open || undefined
contentaria-labelledbytitle 部件的 id
contentaria-modal'true'
contentrole'dialog'
progress-textaria-live'polite'
progress-indicatoraria-hidden'true'
next-triggeraria-labeltranslations?.finish | translations?.next
close-triggeraria-labeltranslations?.close
arrowaria-hidden'true'

样式参考 ​

皮肤 ​

@xihan-ui/styles/tour.css 使用 [data-scope="tour"][data-part="root"] 部件选择器,位于 xihan.components 与 xihan.motion 层。覆盖样式使用 xihan.overrides。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-empty''(条件成立时才出现)
rootdata-state'open' | 'closed'
rootdata-stepString(value)
backdropdata-position'anchored' | 'center'
backdropdata-state'open' | 'closed'
spotlightdata-dimmed''(条件成立时才出现)
spotlightdata-state'open' | 'closed'
positionerdata-placement定位引擎算出的实际落位
positionerdata-position'anchored' | 'center'
positionerdata-positioned''(条件成立时才出现)
positionerdata-state'open' | 'closed'
contentdata-placement定位引擎算出的实际落位
contentdata-state'open' | 'closed'
contentdata-stepString(value)
progress-textdata-stepString(value)
progress-indicatordata-countString(count)
progress-indicatordata-stepString(value)
progress-dotdata-complete''(条件成立时才出现)
progress-dotdata-current''(条件成立时才出现)
progress-dotdata-indexString(index)
prev-triggerdata-disabled''(条件成立时才出现)
prev-triggerdata-pressed''(条件成立时才出现)
prev-triggerdata-state'open' | 'closed'
prev-triggerdata-xh-action-control''
prev-triggerdata-xh-action-display'always'
prev-triggerdata-xh-action-profile'text'
prev-triggerdata-xh-action-size'sm'
prev-triggerdata-xh-action-variant'outline'
next-triggerdata-last''(条件成立时才出现)
next-triggerdata-pressed''(条件成立时才出现)
next-triggerdata-state'open' | 'closed'
next-triggerdata-xh-action-control''
next-triggerdata-xh-action-display'always'
next-triggerdata-xh-action-profile'text'
next-triggerdata-xh-action-size'sm'
next-triggerdata-xh-action-variant'solid'
next-triggerdata-xh-ink-surface''
skip-triggerdata-pressed''(条件成立时才出现)
skip-triggerdata-state'open' | 'closed'
skip-triggerdata-xh-action-control''
skip-triggerdata-xh-action-display'always'
skip-triggerdata-xh-action-profile'text'
skip-triggerdata-xh-action-size'sm'
skip-triggerdata-xh-action-variant'ghost'
close-triggerdata-pressed''(条件成立时才出现)
close-triggerdata-xh-action-control''
close-triggerdata-xh-action-display'always'
close-triggerdata-xh-action-profile'icon'
close-triggerdata-xh-action-size'sm'
close-triggerdata-xh-action-variant'ghost'
arrowdata-placement定位引擎算出的实际落位

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-tour-action-radiusnext-trigger
prev-trigger
skip-trigger
border-radiusdefault--xh-shape-controltour 的 next-trigger、prev-trigger、skip-trigger 部件 border-radius 覆盖槽。
--xh-tour-arrow-sizearrow--xh-_overlay-arrow-sizedefault--xh-overlay-arrow-sizetour 的 arrow 部件 --xh-_overlay-arrow-size 覆盖槽。
--xh-tour-backdrop-bgbackdropbackgrounddefault--xh-bg-overlaytour 的 backdrop 部件 background 覆盖槽。
--xh-tour-backdrop-layerbackdropz-indexdefault--xh-_layertour 的 backdrop 部件 z-index 覆盖槽。
--xh-tour-bgarrow
content
backgrounddefault--xh-material-elevated-bgtour 的 arrow、content 部件 background 覆盖槽。
--xh-tour-borderarrow
content
borderdefault--xh-material-elevated-bordertour 的 arrow、content 部件 border 覆盖槽。
--xh-tour-close-bg-activeclose-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedtour 的 close-trigger 部件 background-color 覆盖槽。
--xh-tour-close-bg-hoverclose-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertour 的 close-trigger 部件 background-color 覆盖槽。
--xh-tour-close-fgclose-triggercolordefault--xh-fg-mutedtour 的 close-trigger 部件 color 覆盖槽。
--xh-tour-close-fg-hoverclose-triggercolordisabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-fg-focus-visible
--xh-_action-variant-fg-hover
--xh-_action-variant-fg-pressed
tour 的 close-trigger 部件 color 覆盖槽。
--xh-tour-close-radiusclose-triggerborder-radiusdefault--xh-shape-controltour 的 close-trigger 部件 border-radius 覆盖槽。
--xh-tour-close-sizeclose-trigger
content
title
block-size
inline-size
padding-inline-end
default
has([data-scope='tour'][data-part='close-trigger'])
xh-action-profile=icon
--xh-_action-profile-visual-size
--xh-control-h-sm
tour 的 close-trigger、content、title 部件 block-size、inline-size、padding-inline-end 覆盖槽。
--xh-tour-description-fgdescriptioncolordefault--xh-fg-mutedtour 的 description 部件 color 覆盖槽。
--xh-tour-fgcontent
root
colordefault--xh-fg-default
--xh-material-elevated-fg
tour 的 content、root 部件 color 覆盖槽。
--xh-tour-gapcontentgapdefault--xh-space-2tour 的 content 部件 gap 覆盖槽。
--xh-tour-icon-sizeclose-trigger
content
next-trigger
prev-trigger
root
skip-trigger
--xh-icon-sizedefault--xh-_action-profile-glyph-size
--xh-glyph-size-md
tour 的 close-trigger、content、next-trigger、prev-trigger、root、skip-trigger 部件 --xh-icon-size 覆盖槽。
--xh-tour-max-hcontentmax-block-sizedefault--xh-overlay-max-htour 的 content 部件 max-block-size 覆盖槽。
--xh-tour-max-wcontentmax-inline-sizedefault--xh-overlay-max-w-lgtour 的 content 部件 max-inline-size 覆盖槽。
--xh-tour-next-bgnext-trigger--xh-ink-surface
background-color
default
focus-visible
xh-ink-surface
--xh-_action-variant-bg-focus-visible
--xh-_action-variant-bg-rest
tour 的 next-trigger 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-tour-next-bg-hovernext-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertour 的 next-trigger 部件 background-color 覆盖槽。
--xh-tour-next-fgnext-triggercolordefault
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-fg-focus-visible
--xh-_action-variant-fg-hover
--xh-_action-variant-fg-pressed
--xh-_action-variant-fg-rest
tour 的 next-trigger 部件 color 覆盖槽。
--xh-tour-next-shadownext-triggerbox-shadowdefaultnonetour 的 next-trigger 部件 box-shadow 覆盖槽。
--xh-tour-positioner-layerpositionerz-indexdefault--xh-_layertour 的 positioner 部件 z-index 覆盖槽。
--xh-tour-positioner-paddingpositionerpaddingposition=center--xh-space-4tour 的 positioner 部件 padding 覆盖槽。
--xh-tour-progress-dot-bgprogress-dotbackgrounddefault--xh-border-defaulttour 的 progress-dot 部件 background 覆盖槽。
--xh-tour-progress-dot-bg-completeprogress-dotbackgroundcomplete--xh-border-strongtour 的 progress-dot 部件 background 覆盖槽。
--xh-tour-progress-dot-bg-currentprogress-dotbackgroundcurrent--xh-bg-brandtour 的 progress-dot 部件 background 覆盖槽。
--xh-tour-progress-fgprogress-textcolordefault--xh-fg-subtletour 的 progress-text 部件 color 覆盖槽。
--xh-tour-progress-font-sizeprogress-textfont-sizedefault--xh-text-caption-sizetour 的 progress-text 部件 font-size 覆盖槽。
--xh-tour-progress-indicator-gapprogress-indicatorgapdefault--xh-space-1tour 的 progress-indicator 部件 gap 覆盖槽。
--xh-tour-pxcontentpadding-inlinedefault--xh-surface-px-mdtour 的 content 部件 padding-inline 覆盖槽。
--xh-tour-pycontentpadding-blockdefault--xh-surface-py-mdtour 的 content 部件 padding-block 覆盖槽。
--xh-tour-radiuscontentborder-radiusdefault--xh-shape-overlaytour 的 content 部件 border-radius 覆盖槽。
--xh-tour-shadowcontentbox-shadowdefault--xh-material-elevated-shadowtour 的 content 部件 box-shadow 覆盖槽。
--xh-tour-skip-trigger-pxnext-trigger
prev-trigger
skip-trigger
padding-inlinedefault--xh-_action-profile-padding-inlinetour 的 next-trigger、prev-trigger、skip-trigger 部件 padding-inline 覆盖槽。
--xh-tour-spotlight-layerspotlightz-indexdefault--xh-_layertour 的 spotlight 部件 z-index 覆盖槽。
--xh-tour-spotlight-radiusspotlightborder-radiusdefault--xh-_tour-spotlight-radiustour 的 spotlight 部件 border-radius 覆盖槽。
--xh-tour-spotlight-ringspotlightbox-shadowdefault--xh-ring-focustour 的 spotlight 部件 box-shadow 覆盖槽。
--xh-tour-spotlight-shroudspotlightbox-shadowdimmed--xh-bg-overlaytour 的 spotlight 部件 box-shadow 覆盖槽。
--xh-tour-title-fgtitlecolordefault--xh-fg-defaulttour 的 title 部件 color 覆盖槽。
--xh-tour-title-font-sizetitlefont-sizedefault--xh-text-heading-3-sizetour 的 title 部件 font-size 覆盖槽。
--xh-tour-title-font-weighttitlefont-weightdefault--xh-text-heading-3-weighttour 的 title 部件 font-weight 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 切换 · 指示与换位 · 出现(锚定面板)(见动效规范)。

关键帧 xh-tour-spotlight-in · xh-tour-spotlight-out 随皮肤自带,不引用别处文件里的名字;共享关键帧 xh-fade-in · xh-fade-out · xh-overlay-pop-in · xh-pop-out 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立;background-color · block-size · border-radius · inline-size · inset-block-start · inset-inline-start 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

皮肤之外还有一段:退场由适配器的退场闸门把关,动画播完才真收起。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License