使用了rc-danmaku
组件地址: 查看地址
本身不支持loop循环弹出, 结合组件内置的方法和hooks特性实现了 弹幕加载完成重复渲染
主要用到的方法有 onBulletOut、danmakuIns.getRestAmount()、push
实现过程:
- onBulletOut 方法中获取剩余弹幕数
- 定义count 存储剩余弹幕数
- 当剩余数里为0时再次发送弹幕
- 加入计时器避免初始化时弹幕重叠
import React, { useEffect, useRef, useState } from 'react';
import Danmaku from 'rc-danmaku';
// dataSource 弹幕数据, 从父组件获取
const TestDanmaku: React.FC = ({ dataSource }) => {
const danmakuInsRef = useRef<Danmaku | null>(null);
const [count, setCount] = useState(0);
// 弹幕一次性全部发送方法
const renderDanmaku = () => {
// console.log('====renderDanmaku out====');
if (dataSource.length > 0) {
dataSource.map((item) => {
const text = item.nickName + ':' + item.content;
const textDom = <span style={{ fontSize: '16px' }}>{text}</span>;
danmakuInsRef.current.push(textDom);
});
}
};
useEffect(() => {
const danmakuIns = new Danmaku('.danmaku-wrapper', {
maxRow: 0,
rowHeight: 32,
onBulletOut() {
// 关键代码, 弹幕消失时计算弹幕队列中剩余的数量
// console.log('====bullet out====', danmakuIns.getRestAmount());
setCount(danmakuIns.getRestAmount());
},
onQueueRunOut() {
// setCount(danmakuIns.getRestAmount());
// console.log('====queue run out====', danmakuIns.getRestAmount());
},
});
danmakuInsRef.current = danmakuIns;
}, []);
useEffect(() => {
setTimeout(() => {
// 延时避免字体重叠
renderDanmaku();
}, 500);
}, [dataSource]);
useEffect(() => {
if (danmakuInsRef.current) {
// 当剩余数为0时再次发送弹幕
(count === 0 && dataSource.length) && setTimeout(() => {
renderDanmaku();
}, 1000);
}
// console.log('out', count)
}, [count]);
return (
<div className="test-danmaku">
<div
className="danmaku-wrapper"
style={{
width: '100%',
height: '96px',
backgroundColor: '#fff',
marginTop: '10px',
}}
/>
{/* <button
type="button"
onClick={(): void => {
if (danmakuInsRef.current) {
danmakuInsRef.current.push('Hello World!');
}
}}
>
发送弹幕
</button> */}
</div>
);
};
export default TestDanmaku;