lumen-tour
v0.3.0
Published
Lightweight zero-dependency product tour / onboarding guide. TypeScript + native CSS.
Maintainers
Readme
lumen-tour
轻量级、零依赖的产品引导(Product Tour / Onboarding Guide)库。TypeScript + 原生 CSS,不依赖任何框架,可在 Vanilla / React / Vue 等任意项目中使用。
特性
- 🪶 零依赖:无运行时依赖,打包体积小
- 🎯 自动定位:卡片自动选择目标下方/上方,放不下自动翻转,支持手动指定方向
- ⌨️ 键盘导航:
→下一步、←上一步、Esc跳过 - 🎨 可定制:按钮文案、遮罩颜色、挖孔边距均可配置;支持完全自定义卡片内容
- 🔄 跟随重定位:resize / scroll(含嵌套滚动容器)时自动跟随目标
- 🧩 步骤自动跳过:target 无法解析的步骤自动跳过,不中断引导
安装
npm install lumen-tour引入样式(引导卡片的默认样式):
import 'lumen-tour/style.css';快速开始
import { createTour } from 'lumen-tour';
import 'lumen-tour/style.css';
const tour = createTour({
steps: [
{
target: '#logo', // CSS 选择器或 HTMLElement
title: '欢迎来到 Lumen',
description: '这里是 logo,点击可返回首页。',
media: '/img/step1.png' // 可选插图
},
{
target: document.querySelector('#menu')!,
title: '导航菜单',
description: '在这里切换功能模块。',
placement: 'right' // 可选:手动指定卡片方向
}
],
onNext: async (ctx) => {
// 异步校验示例:返回 false 阻止前进
const ok = await validateStep(ctx.index);
return ok;
},
onFinish: () => {
console.log('引导完成');
}
});
tour.start();API
createTour(options: TourOptions): TourInstance
创建引导实例。
TourOptions
| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| steps | TourStep[] | (必填) | 引导步骤列表 |
| texts | Partial<ButtonTexts> | 见下 | 覆盖按钮文案 |
| overlayColor | string | rgba(0,0,0,0.5) | 遮罩颜色 |
| padding | number \| number[] | 8 | 挖孔相对目标元素的内边距(px),CSS 风格简写:number/[v] 四周等距,[t, h] 上下 t、左右 h,[t, h, b] 上 t、左右 h、下 b,[t, r, b, l] 上/右/下/左独立控制 |
| hideSkipOnLast | boolean | false | 到达最后一步时是否隐藏"跳过"按钮 |
| keyboard | boolean | true | 是否启用键盘导航(→ 下一步、← 上一步、Esc 跳过) |
| onNext | (ctx) => void \| boolean \| Promise<void \| boolean> | — | 点击"下一步"时触发;返回 false 可阻止前进(支持异步校验) |
| onPrev | (ctx) => void | — | 点击"上一步"时触发 |
| onSkip | (ctx) => void | — | 点击"跳过"或按 Esc 时触发 |
| onFinish | (ctx) => void | — | 引导完成(最后一步点"完成")或所有步骤无效结束时触发 |
| onStepChange | (ctx) => void | — | 每次切换到新步骤后触发 |
TourStep
| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| target | string \| HTMLElement | (必填) | 目标元素,CSS 选择器或元素本身 |
| title | string | — | 卡片标题,支持受限 HTML(经白名单清洗,见下) |
| description | string | — | 卡片描述文本,支持受限 HTML(经白名单清洗,见下) |
| media | string | — | 卡片顶部插图 URL |
| placement | Placement | 自动 | 卡片相对目标的方向,共 12 个:基础方向 'bottom' \| 'top' \| 'left' \| 'right'(贴边 + 交叉轴居中);组合方向 'topLeft' \| 'topRight' \| 'bottomLeft' \| 'bottomRight'(贴上/下边,左/右缘对齐目标)与 'leftTop' \| 'leftBottom' \| 'rightTop' \| 'rightBottom'(贴左/右边,上/下缘对齐目标)。不传则自动(下方优先,放不下翻转上方);指定方向主轴放不下时回退自动策略 |
| renderMedia | (container, ctx) => void | — | 传入则完全接管卡片插图区(替代 media 图片),可渲染视频等任意 HTML |
| renderContent | (container, ctx) => void | — | 传入则完全接管卡片内容区(按钮区除外),可渲染任意 HTML |
注意:
media/title/description仅在未传renderContent时生效;renderContent优先级最高;renderMedia优先于media,且不受renderContent影响(需接管整个卡片请用renderContent)。
title / description 的富文本与 XSS 防护
title 与 description 支持直接渲染 HTML(可加粗、插图、超链接等),但在渲染前会经过白名单消毒,剥离脚本与攻击向量:
- 允许的标签:
a b strong i em u ins s del strike code kbd pre span div p br hr ul ol li blockquote q cite h1-h6 img sub sup mark small abbr figure figcaption等;其余标签解包保留文本,script/iframe/object/embed/svg/template/form等危险标签连同内容一并删除。 - 允许的属性:
href src alt title class style target rel width height等;所有on*事件处理器属性一律移除。 - 协议白名单:
href/src仅放行http(s)、相对路径、锚点、mailto/tel;javascript:/vbscript:/file:、data:text/、data:image/svg等危险协议清空(img的data:image/png|jpeg|gif|webp放行)。 - 内联 style 清洗:阻断
expression()、-moz-binding、behavior、url(javascript:)等 CSS 注入;外链<a target="_blank">自动补noopener noreferrer。
若需渲染不受限的 HTML,请改用 renderContent 自行控制(注意自行处理 XSS)。
ButtonTexts
| 属性 | 默认值 |
| --- | --- |
| prev | '上一步' |
| next | '下一步' |
| skip | '跳过' |
| finish | '完成' |
StepContext
传给所有回调与 renderContent 的上下文:
| 属性 | 类型 | 说明 |
| --- | --- | --- |
| index | number | 当前步索引(从 0 开始) |
| total | number | 总步数 |
| step | TourStep | 当前步骤配置 |
TourInstance 方法
| 方法 | 说明 |
| --- | --- |
| start() | 启动引导(从第一个有效步骤开始;可重复调用,已启动则忽略) |
| next() | 前进到下一步(受 onNext 校验约束) |
| prev() | 返回上一步 |
| skip() | 跳过引导并触发 onSkip |
| finish() | 结束引导并触发 onFinish |
| goTo(index) | 跳转到指定步骤(越界忽略) |
| destroy() | 销毁实例并移除 DOM;之后不可再用,需重新 createTour() |
事件与回调说明
onNext拦截:返回false(或Promise<false>)时停留在当前步。等待异步结果期间重复点击会被防重入,且用户若已 skip/finish/导航离开则不再前进。- 步骤自动跳过:某步
target在文档中找不到时会跳到下一个有效步骤;所有步骤都无效时直接结束并触发onFinish。 - destroy 后调用:任何实例方法都会抛错,提示重新
createTour()。
自定义卡片内容
const tour = createTour({
steps: [
{
target: '#upload',
renderContent(container, ctx) {
container.innerHTML = `
<h3>上传文件(${ctx.index + 1}/${ctx.total})</h3>
<p>支持拖拽上传,单文件不超过 100MB。</p>
<video src="/demo.mp4" controls></video>
`;
}
}
]
});开发
npm run dev # 启动 demo 页
npm test # 运行测试(vitest)
npm run build # 构建产物到 dist/License
MIT
