Danmaku
danmaku弹幕引擎 · 轨道分配防重叠(等速模型·第二条入场后发车永不追尾) · scroll 滚动/top 顶部/bottom 底部三模式 + 轨道数/速度/密度(low/normal/high)/占屏比/透明度/暂停 + pointer-events none 穿透到底层视频 · 几何抽纯函数(allocateTrack/scrollDuration/estimateWidth)带单测 · 直播旗舰
用法
基础用法
叠在视频上的弹幕层(absolute inset-0)。items 受控、只增不改,新增项自动入场并按轨道防重叠飘过。
直播画面
tsx
<div className="relative aspect-video">
<video ... />
<Danmaku
items={[
{ id: "x1", text: "弹幕飘过~" },
{ id: "x2", text: "主播好飒!", color: "var(--color-chart-1)", bold: true },
]}
tracks={4}
speed={100}
/>
</div>顶部停留弹幕
mode='top' 的弹幕居中停留在顶部一段时间(非滚动),适合公告/置顶。
直播画面
tsx
<Danmaku
items={[
{ id: "y0", text: "今晚 8 点抽奖,关注不迷路", mode: "top", bold: true },
{ id: "y1", text: "前排围观" },
]}
tracks={4}
/>高密度 · 快速
density='high' 时无空闲轨道也强挤(不丢弹幕);speed 提速、tracks 加轨道。
直播画面
tsx
<Danmaku items={items} density="high" speed={160} tracks={6} />何时用
直播/视频画面上覆盖飘动弹幕。绝对定位铺满父容器且 pointer-events 穿透,配合 LivePlayer 的 overlay 插槽使用。要弹幕就用本组件;要消息列表/公屏滚动用 LiveChat。
导入
ts
import { Danmaku, allocateTrack, densityGap, estimateWidth, leastBusyTrack, scrollDuration, trackFreeTime } from "@hulianui/ui"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| items* | DanmakuItem[] | — | 受控弹幕流,只增不改既有项;新增项自动入场(内部按 item.id 去重,仅对未上屏的入场) |
| tracks | number | 4 | 滚动轨道数 |
| speed | number | 100 | 滚动速度 px/s |
| density | "low" | "normal" | "high" | "normal" | 密度:决定轨道安全间隙 + 无空闲轨道时是否强挤 |
| area | number | 1 | 弹幕占用容器高度比 0–1,1=满屏 |
| opacity | number | 1 | 整体不透明度 |
| paused | boolean | false | 暂停所有动画 |
| className | string | — | 容器自定义类 |
DanmakuItem:{ id: string; text: ReactNode; mode?: "scroll"|"top"|"bottom"; color?: string; size?: "sm"|"md"|"lg"; bold?: boolean }。mode 默认 scroll,size 默认 md,color 默认继承前景 token。
禁忌 / 坑
items是只增受控流:组件内部记录已上屏 id,只对「新增且未上屏」的项入场。改写既有项不会重新触发动画;要让同一条再飞一次须换新id。- 长直播务必裁剪
items(如slice(-60)),否则数组无限膨胀;组件只对新项做动画,旧项留在数组不影响渲染但占内存。 - 组件铺满父容器且
pointer-events: none穿透,父容器需position: relative+overflow: hidden。
相关
Table · Book3D · ProTable · PricingTable · JsonViewer · EditableTable
Playground
直播画面
<div className="relative aspect-video">
<video ... />
<Danmaku items={items} tracks={4} speed={100} density="normal" />
</div>