在不少App的H5首页,常常会看到顶部的轮播的消息流,相似于弹幕,展现给用户,增长营销感,例如某电商首页:javascript
要实现相似的功能,该如何设计一个通用的组件?css
若是单个弹幕展现时间等于弹幕间隔时间,利用
aniamtion
keyframes
50% 以后隐藏弹幕便可; 若是单个弹幕展现时间不等于弹幕间隔时间,经过 js 控制 css 的 keyframes 在W3C规范中没法实现,可是能够经过animation-delay + 组件销毁重建实现;html
弹幕的无限循环轮播经过 CSS 动画
animation-iteration-count: infinite
,动画总时间为一个弹幕显示 + 隐藏的总时间前端
弹幕展现规则以下图所示 java
// 弹幕容器组件 <Barrage barrageList={barrageList} duration={4} /> // 弹幕渲染组件 duration 表示单个弹幕总时间 <BarrageItem barrageContent={barrageList[barrageIndex]} duration={duration} /> 复制代码
每隔 duration
时间展现下一个弹幕web
const { duration } = this.props; this.timer = setInterval(() => { const { barrageList } = this.props; const { barrageIndex } = this.state; this.setState({ barrageIndex: (barrageIndex + 1) % barrageList.length // 这里取模是为了循环展现弹幕数据 }); }, duration * 1000); 复制代码
function BarrageItem ({ barrageContent, duration }) { return ( <div className='barrage' style={{ animation: `showBarrage ${duration}s ease-in-out infinite` }}> <div className='thumb' style={{ backgroundImage: `url(${barrageContent.avatar})` }} /> <div className='text'> {barrageContent.text} </div> </div> ); } 复制代码
CSS 动画飞入飞出,且 动画一直无限循环 来实现弹幕轮播npm
@keyframes showBarrage { 0% { opacity: 0; left: -100%; } 5% { opacity: 1; left: .06rem; } 45% { opacity: 1; left: .06rem; } 50% { opacity: 0; left: -100%; } 100% { opacity: 0; left: -100%; } } 复制代码
这样就实现一个最简单的飞入飞出的弹幕了,效果以下: canvas
弹幕的无限循环轮播不经过 CSS 动画,而是经过组件的销毁与重建;后端
弹幕显示时间为动画持续时间,弹幕间隔时间为动画延迟时间(由于
animation-iteration-count: infinite
状况下,延迟时间只在首次动画生效,后续每个动画循环不会执行延迟效果)服务器
弹幕展现规则以下图所示
// 弹幕容器组件 <Barrage barrageList={barrageList} showTime={3} gapTime={1} /> // 弹幕渲染组件 <BarrageItem barrageContent={barrageList[barrageIndex]} showTime={3} gapTime={1} /> 复制代码
每隔 showTime + gapTime
时间展现下一个弹幕
const { duration } = this.props; this.timer = setInterval(() => { const { barrageList } = this.props; const { barrageIndex, showBarrage } = this.state; this.setState({ barrageIndex: (barrageIndex + 1) % barrageList.length, // 这里取模是为了循环展现弹幕数据 showBarrage: !showBarrage }); }, (showTime + gapTime) * 1000); // 经过组件的key不一样来销毁并重建组件 render () { const { barrageList, showTime, gapTime } = this.props; const { barrageIndex, showBarrage } = this.state; return showBarrage ? <BarrageItem key={'before'} barrageContent={barrageList[barrageIndex]} showTime={showTime} gapTime={gapTime} /> : <BarrageItem key={'after'} barrageContent={barrageList[barrageIndex]} showTime={showTime} gapTime={gapTime} />; } 复制代码
function BarrageItem ({ barrageContent, duration }) { return ( <div className='common-barrage' style={{ animation: `showBarrage ${showTime}s ease-in-out ${gapTime}s` }}> <div className='thumb' style={{ backgroundImage: `url(${barrageContent.avatar})` }} /> <div className='text'> {barrageContent.txt} </div> </div> ); } 复制代码
CSS 动画飞入飞出,且 动画一直无限循环 来实现弹幕轮播
@keyframes showBarrage { 0% { opacity: 0; left: -100%; } 10% { opacity: 1; left: 6px; } 90% { opacity: 1; left: 6px; } 100% { opacity: 0; left: -100%; } } 复制代码
效果以下:
服务端推送,数据发送方为服务端,接收方为客户端,服务端每隔一段时间就推送必定数量的弹幕数据给客户端,客户端拿到数据后更新本地弹幕数据队列,展现顺序依推入弹幕的顺序执行。
首先须要了解下 Websocket
, 参考大神的 阮一峰博客 与 Websocket MDN
做为一名前端,天然而然想到结合基于 Nodejs 的 WebSocket 框架 Socket.io 来实现弹幕数据的推送
首先基于 Nodejs 的 http 模块和 WebSocket 框架 Socket.io 搭建一个简单的推送服务器, 每隔一段时间往客户端推送必定量的弹幕数据
搭建过程参考官方文档 [搭建基于Node HTTP服务器的Socket](https://socket.io/docs/#Using-with-Node-http-server)
> npm init
> npm install --save socket.io
复制代码
const socket = require('socket.io'); const http = require('http'); const server = http.createServer(/** 定义一个路由处理函数 */); server.listen(8080); const io = socket(server); let timer = null; // 模拟弹幕数据 io.on('connection', socket => { console.log('连上了'); // 连上以后隔一段时间往客户端推送弹幕数据,每次推送三条随机弹幕 timer = setInterval(() => { const obj = [ { avatar: 'xxx1.png', txt: '弹幕' + Math.floor(Math.random() * 100) }, { avatar: 'xxx2.png', txt: '弹幕' + Math.floor(Math.random() * 100) }, { avatar: 'xxx3.png', txt: '弹幕' + Math.floor(Math.random() * 100) } ] socket.send(JSON.stringify(obj)) // 传输序列化后的字符串数据 }, 6000) socket.on('disconnect', () => { console.log('断开了'); clearInterval(timer); }) }) 复制代码
前端这边经过安装 Socket.io
的客户端,便可监听并接收从服务端推送过来的数据
npm install --save socket.io-client
建立并链接到客户端 socket.io-client
// // Barrage.js import io from 'socket.io-client'; const socket = io('ws://localhost:8080'); // 监听message事件并更新本地弹幕数据 const [barrageList, getBarrageList] = useState([]); useEffect(() => { socket.on('message', (data) => { getBarrageList(oldBarrageList => { console.log([...oldBarrageList, ...JSON.parse(data)]) return [...oldBarrageList, ...JSON.parse(data)]; }); }) }, []); 复制代码
效果以下,右边控制台打印的是每次接收到服务端的推送弹幕后的本地数据
王司徒镇楼
视频弹幕主要须要考虑以下几个问题
在这里咱们考虑一种比较简单的状况
固定轨道数
弹幕移动速度固定
统一轨道上弹幕不重叠
弹幕颜色随机
轨道上下不重叠
弹幕数据来自于服务端推送(模拟用户输入弹幕)
最后,这里推荐一个比较好用的基于 canvas 的视频弹幕组件 Barrage UI