特性
嵌套导航
点击切换 story,滑动切换分组
视频 story
自动播放,带声音开关
自动播放
每个 story 可配置计时
3D 过渡
立方体、翻转、淡入、缩放、滑动
进度条
基于 canvas 的分段进度
图片与视频
两种媒体类型都 支持
虚拟化
DOM 里只有 3 张幻灯片
双击点赞
双击时的爱心动画
桌面端导航
桌面端的箭头按钮
story 圆环
Instagram 风格的头像圆环
泛型类型
用自定义数据扩展 StoryItem
Render Props
每个界面元素都可定制
URL 状态
可分享的 ?story=group.story 链接
已观看状态
已看圆环与续播跨刷新保留
安装
bash
别忘了引入样式:
typescript
图标
默认页眉使用
lucide-react 作为图标。如果你想换一套图标库,可以用 renderHeader 和 renderNavigation 提供自己的实现。快速上手
StoriesOverlay 组件渲染一个全屏 Stories Player。搭配 StoriesRingList 作为 Instagram 风格的入口。传入一组 StoriesGroup 对象,并用 isOpen.
tsx
在线演示
StoriesPlayer.tsx
点圆环打开播放器。点左右两侧切换 story,滑动切换用户。
URL 状态
查看在线演示 →StoriesUrlOverlay 是一个独立组件,它的打开状态存放在地址栏里。两条轴共 用一个参数 —— ?story=<group>.<story> —— 于是正在播放的 story 就有了可分享、可收藏、能用返回键关闭的链接。用 useOverlayUrlState 和 urlIndexTwoAxisKey构建控制器,再作为 controller.
tsx
- 打开时压入 一条 历史记录。滑动 story 和 切换用户都是 替换 它,因此导航 N 次也不会多出记录,退一步永远就是关闭播放器。返回键关闭播放器,不会逐个后退 story。
- 内层导航也会被记录。 story 索引不会被冻结在分组粒度上 —— 在某个用户的 story 之间前进时会更新
?story=2.n,因此深链 能精确落到那一个 story。 - 只有在应用内部打开播放器时返回键才会关闭它 —— 因为那次链接压入了一条记录。在新标签页里直接打开的分享链接背后没有历史,浏览器返回会离开站点;这时用 ✕ 按钮或 Escape 就地移除参数并留在页面上。
- 指向不存在的分组或 story 的参数 —— 过期的书签、手改的值、超出分组末尾的 story —— 会从 URL 中移除,而不是打开相邻的那个。
带路由的应用 —— 请传入适配器。 绕过路由器直接写 history.pushState 会让它的 location 过期,下一次导航就会把参数丢掉:
tsx
稳定的链接。 分组默认是按位置的,所以收藏下来的 ?story=2.0 在信息流重新排序后就会打开另一个用户。请改用稳定 id 来寻址分组 —— outerCodec 把 id 写进 URL, outerLocator 负责找到它在哪。story 那一半仍然是解析出的分组内的普通索引。
tsx
无限信息流。 翻页是 outerLocator