Gathering detailed insights and metrics for rc-danmaku
Gathering detailed insights and metrics for rc-danmaku
Gathering detailed insights and metrics for rc-danmaku
Gathering detailed insights and metrics for rc-danmaku
React弹幕组件 / React danmaku(or bullet screen) component
npm install rc-danmaku
Typescript
Module System
Node Version
NPM Version
JavaScript (63.1%)
TypeScript (29.24%)
HTML (7.66%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
45 Stars
20 Commits
7 Forks
2 Watchers
2 Branches
1 Contributors
Updated on Apr 30, 2025
Latest Version
1.2.0-alpha.1
Package Id
rc-danmaku@1.2.0-alpha.1
Unpacked Size
71.22 kB
Size
13.79 kB
File Count
20
NPM Version
10.7.0
Node Version
18.20.4
Published on
Aug 22, 2024
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
3
36
🚀 React 弹幕组件 - 支持 React 17/18 和 TypeScript
🌟 已更新支持React18 🐞 若发现问题欢迎提 issue,有功能需求欢迎提 pr 或者在 issue 中反馈。
🔗 https://bowenz.github.io/pages/rc-danmaku/
npm install rc-danmaku -S
复制下方代码可以直接使用(代码 TypeScript 版本)
1import React, { useEffect, useRef } from 'react'; 2import Danmaku from 'rc-danmaku'; 3 4const TestDanmaku: React.FC = () => { 5 const danmakuInsRef = useRef<Danmaku | null>(null); 6 7 useEffect(() => { 8 const danmakuIns = new Danmaku('.danmaku-wrapper'); 9 danmakuInsRef.current = danmakuIns; 10 }, []); 11 12 return ( 13 <div className="test-danmaku"> 14 <div 15 className="danmaku-wrapper" 16 style={{ 17 width: '300px', 18 height: '200px', 19 backgroundColor: '#000', 20 }} 21 /> 22 <button 23 type="button" 24 onClick={(): void => { 25 if (danmakuInsRef.current) { 26 danmakuInsRef.current.push('Hello World!'); 27 } 28 }} 29 > 30 发送弹幕 31 </button> 32 </div> 33 ); 34}; 35 36export default TestDanmaku;
1// 第一个参数是弹幕容器,可以传string类型的选择器,或者直接传dom元素 2// 第二个object类型的参数是可选参数,包含弹幕配置,里边的所有项均不是必填项 3const danmakuIns = new Danmaku('.danmaku-wrapper', { 4 rowHeight: 60, // 弹幕轨道高度,默认40(单位px) 5 speed: 120, // 弹幕速度,默认100(单位px/s) 6 opacity: 1, // 弹幕透明度,默认为1,范围 0-1 7 maxRow: 0, // 弹幕最大轨道数,会根据容器高度自动计算,也可以手动赋值(此处设为0表示使用自动计算高度) 8 minGapWidth: 30, //弹幕之前的最小间隔宽度,默认值20(单位px) 9 // 每个弹幕进入时触发 10 onBulletIn() { 11 console.log('====bullet in===='); 12 }, 13 // 每个弹幕消失时触发 14 onBulletOut() { 15 console.log('====bullet out===='); 16 }, 17 // 队列中的弹幕发送完时触发(每次发送弹幕都会检查,不管用何种方式发送,手动清空队列不会触发该事件) 18 onQueueRunOut() { 19 console.log('====queue run out===='); 20 }, 21});
初始化后,可调用实例方法发送弹幕
1const danmakuIns = new Danmaku('.danmaku-wrapper'); 2 3// 发送文本 4danmakuIns.push('test string'); 5 6// 发送指定颜色的文本 7danmakuIns.push('test string', { 8 color: 'red', 9}); 10 11// 发送React组件 12danmakuIns.push(<TestReactComponent />); 13 14// 直接发送文本 15// emit与push的区别是,push会在屏幕中没有空闲位置时暂不发送,等有空位时再发送, 16// emit会不管有没有空位直接发送,传参规则和push完全一样 17danmakuIns.emit('test string'); 18 19// 批量发送 20danmakuIns.pushAll(['test1', 'test2', 'test3']); 21 22// 暂停 23danmakuIns.pause(); 24 25// 继续 26danmakuIns.resume(); 27 28// 销毁 29danmakuIns.destroy(); 30 31// 查看弹幕队列中剩余的数量 32danmakuIns.getRestAmount(); 33 34// 清空排队中的弹幕队列(已发送的不会被清,不会触发onQueueRunOut事件) 35danmakuIns.clearQueue();
1import React, { useEffect, useRef, useState } from 'react'; 2import styled from 'styled-components'; 3import Danmaku from 'rc-danmaku'; 4 5const textArr = Array.from( 6 '通过对平面中竖直和水平方向的分析我们将宽泛的弹幕重叠问题收敛为轨道中相邻弹幕两两之间的追及问题最终获得了将候选弹幕挂载到合适轨道中的调度策略' 7); 8 9function getRandomIndex(length: number): number { 10 return Math.floor(Math.random() * length); 11} 12 13function getRandomText(): string { 14 const length = Math.floor(Math.random() * 19) + 1; 15 return Array(length) 16 .fill(null) 17 .map(() => { 18 return textArr[getRandomIndex(textArr.length)]; 19 }) 20 .join(''); 21} 22 23const TestDanmaku: React.FC = () => { 24 const danmakuInsRef = useRef<Danmaku | null>(null); 25 const [showColor, setShowColor] = useState(false); 26 const colorRef = useRef(''); 27 const [isPaused, setIsPaused] = useState(false); 28 29 useEffect(() => { 30 // 第一个参数是弹幕容器,可以传string类型的选择器,或者直接传dom元素 31 // 第二个object类型的参数是可选参数,包含弹幕配置,里边的所有项均不是必填项 32 const danmakuIns = new Danmaku('.danmaku-wrapper', { 33 rowHeight: 60, // 弹幕轨道高度,默认40(单位px) 34 speed: 120, // 弹幕速度,默认100(单位px/s) 35 opacity: 1, // 弹幕透明度,默认为1,范围 0-1 36 maxRow: 5, // 弹幕最大轨道数,会根据容器高度自动计算,也可以手动赋值 37 minGapWidth: 30, //弹幕之前的最小间隔宽度,默认值20(单位px) 38 }); 39 danmakuInsRef.current = danmakuIns; 40 }, []); 41 42 useEffect(() => { 43 if (showColor) { 44 colorRef.current = (document.querySelector( 45 '.color-piker' 46 ) as HTMLInputElement).value; 47 } 48 }, [showColor]); 49 50 useEffect(() => { 51 if (danmakuInsRef.current) { 52 if (isPaused) { 53 danmakuInsRef.current.pause(); 54 } else { 55 danmakuInsRef.current.resume(); 56 } 57 } 58 }, [isPaused]); 59 return ( 60 <Wrapper className="test-danmaku"> 61 <div className="danmaku-wrapper" /> 62 <div> 63 <span>透明度</span> 64 <input 65 type="range" 66 min="0" 67 max="1" 68 step="0.1" 69 onChange={(e): void => { 70 if (danmakuInsRef.current) { 71 const { value } = e.target; 72 danmakuInsRef.current.opacity = Number(value); 73 } 74 }} 75 /> 76 </div> 77 <div> 78 <span>彩色弹幕:</span> 79 <input 80 type="checkbox" 81 onChange={(e): void => { 82 const { checked } = e.target; 83 setShowColor(checked); 84 }} 85 /> 86 87 <input 88 className="color-piker" 89 type="color" 90 defaultValue="#ff0000" 91 style={{ 92 visibility: showColor ? 'visible' : 'hidden', 93 }} 94 onChange={(e): void => { 95 const { value } = e.target; 96 colorRef.current = value; 97 }} 98 /> 99 </div> 100 <button 101 type="button" 102 onClick={(): void => { 103 if (danmakuInsRef.current) { 104 danmakuInsRef.current.emit(getRandomText(), { 105 color: showColor ? colorRef.current : undefined, 106 }); 107 } 108 }} 109 > 110 发送随机文本(过多会重叠) 111 </button> 112 <div> 113 <span>输入文本:</span> 114 <input type="text" className="danmaku-text-input" /> 115 <button 116 type="button" 117 onClick={(): void => { 118 if (danmakuInsRef.current) { 119 const $input = document.querySelector( 120 '.danmaku-text-input' 121 ) as HTMLInputElement; 122 if ($input.value && $input.value.trim()) { 123 danmakuInsRef.current.emit($input.value, { 124 color: showColor ? colorRef.current : undefined, 125 }); 126 } 127 128 $input.value = ''; 129 $input.focus(); 130 } 131 }} 132 > 133 发送 134 </button> 135 </div> 136 <button 137 type="button" 138 onClick={(): void => { 139 if (danmakuInsRef.current) { 140 danmakuInsRef.current.emit(<TestNode>react node</TestNode>); 141 } 142 }} 143 > 144 发送react节点 145 </button> 146 <button 147 type="button" 148 onClick={(): void => { 149 if (danmakuInsRef.current) { 150 danmakuInsRef.current.push(getRandomText(), { 151 color: showColor ? colorRef.current : undefined, 152 }); 153 } 154 }} 155 > 156 推送随机文字到发送队列(过多不会重叠,会延迟发送) 157 </button> 158 <button 159 type="button" 160 onClick={(): void => { 161 if (danmakuInsRef.current) { 162 danmakuInsRef.current.push(<TestNode>react node</TestNode>); 163 } 164 }} 165 > 166 推送React节点到发送队列(过多不会重叠,会延迟发送) 167 </button> 168 <button 169 type="button" 170 onClick={(): void => { 171 if (danmakuInsRef.current) { 172 danmakuInsRef.current.pushAll( 173 Array(20) 174 .fill(null) 175 .map(() => getRandomText()), 176 { 177 color: showColor ? colorRef.current : undefined, 178 } 179 ); 180 } 181 }} 182 > 183 随机推送20条文字弹幕 184 </button> 185 <button 186 type="button" 187 onClick={(): void => { 188 if (danmakuInsRef.current) { 189 danmakuInsRef.current.pushAll( 190 Array(20) 191 .fill(null) 192 .map(() => <TestNode>react node</TestNode>) 193 ); 194 } 195 }} 196 > 197 随机推送20条React节点 198 </button> 199 <div> 200 {isPaused ? ( 201 <span style={{ color: 'red' }}>暂停中</span> 202 ) : ( 203 <span style={{ color: 'green' }}>运行中</span> 204 )} 205 </div> 206 <div> 207 <button 208 type="button" 209 onClick={(): void => { 210 setIsPaused((p) => !p); 211 }} 212 > 213 {isPaused ? '继续' : '暂停'} 214 </button> 215 </div> 216 <button 217 type="button" 218 onClick={(): void => { 219 if (danmakuInsRef.current) { 220 danmakuInsRef.current.destroy(); 221 alert('组件已经被销毁,任何操作将会无相应,重新刷新页面再测吧'); 222 } 223 }} 224 > 225 销毁(销毁后无法再发送弹幕) 226 </button> 227 </Wrapper> 228 ); 229}; 230 231export default TestDanmaku; 232 233const Wrapper = styled.div` 234 display: flex; 235 flex-direction: column; 236 justify-content: center; 237 align-items: center; 238 height: 100vh; 239 height: calc(100vh - 45px); 240 input[type='text'] { 241 padding: 0.2em; 242 width: 150px; 243 max-width: 150px; 244 } 245 button { 246 outline: none; 247 appearance: none; 248 padding: 0.2em 1.45em; 249 margin: 0.1em; 250 border: 0.15em solid #cccccc; 251 color: #000000; 252 background-color: #cccccc; 253 &:hover { 254 border-color: #7a7a7a; 255 } 256 &:active { 257 background-color: #999999; 258 } 259 } 260 .danmaku-wrapper { 261 width: 90%; 262 height: 60vw; 263 max-height: 500px; 264 background-color: #000; 265 } 266`; 267 268const TestNode = styled.div` 269 width: 100px; 270 height: 30px; 271 background: linear-gradient(90deg, pink, red); 272 border-radius: 20px; 273 color: #fff; 274 line-height: 30px; 275 text-align: center; 276`;
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/14 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
47 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More