<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrapper{
width: 100%;
height: 400px;
background-color: #000;
color: #fff;
position: relative;
overflow: hidden;
font-size: 14px;
}
.right{
position: absolute;
visibility: hidden;
white-space: nowrap;
transform: translateX(100vw);
}
.left{
position: absolute;
white-space: nowrap;
user-select: none;
transition: transform 7s linear; /* 时间相同 越长的弹幕滑动距离越长 所以越快~ */
}
input {
position: absolute;
bottom: 10px;
left: 150px;
width: 300px;
height: 26px;
}
button {
position: absolute;
bottom: 8px;
left: 476px;
width: 100px;
height: 38px;
border-radius: 10px;
font-size: 16px;
}
</style>
</head>
<body>
<div id="wrapper">
<input type="text">
<button>发 送</button>
</div>
<script>
/*
* 弹幕池,每一条通道最多6条弹幕
* */
const MAX_DM_COUNT = 6;
const CHANNEL_COUNT = 10;
let domPool = [];
let danmuPool = [
'弹幕1'
];
let hasPosition = [];
/*
* 初始化
* */
function init() {
let wrapper = document.getElementById('wrapper');
for(let j = 0; j < CHANNEL_COUNT; j++){
let doms = [];
for(let i = 0; i < MAX_DM_COUNT; i++){
// 要全部放进wrapper
let dom = document.createElement('span');
wrapper.appendChild(dom);
// 初始化dom的位置 通过设置className
dom.className = 'right';
// DOM的通道是固定的 所以设置好top就不需要再改变了
dom.style.top = j * 20 + 'px';
// 放入改通道的DOM池
doms.push(dom);
// 每次到transition结束的时候 就是弹幕划出屏幕了 将DOM位置重置 再放回DOM池
dom.addEventListener('transitionend', () => {
dom.className = 'right';
dom.style.transform = null;
// 在滚动结束以后,初始化数组
domPool[j].push(doms)
})
// 刚开始就是初始化数组,每个轨道添加最大量数组
}
domPool.push(doms);
}
// hasPosition 标记每个通道目前是否有位置
for (let i = 0; i < CHANNEL_COUNT; i++) {
hasPosition[i] = true;
}
}
/*
* 获取一个可以发射弹幕的通道 没有则返回-1
*/
function getChannel() {
for(let i = 0; i < CHANNEL_COUNT; i++){
if (hasPosition[i] && domPool[i].length) return i;
}
return -1
}
/*
* 根据DOM和弹幕信息 发射弹幕
*/
function shootDanmu(dom, text, channel) {
// console.log('biu~ [' + text + ']');
dom.innerText = text;
// 如果为每个弹幕设置 transition 可以保证每个弹幕的速度相同 这里没有保证速度相同
// dom.style.transition = `transform ${7 + dom.clientWidth / 100}s linear`;
// 设置弹幕的位置信息 性能优化 left -> transform
dom.style.transform = `translateX(${-dom.clientWidth}px)`;
dom.className = 'left';
hasPosition[channel] = false;
// 弹幕全部显示之后 才能开始下一条弹幕
// 大概 dom.clientWidth * 10 的时间 该条弹幕就从右边全部划出到可见区域 再加1秒保证弹幕之间距离
setTimeout(() => {
hasPosition[channel] = true;
}, dom.clientWidth * 10 + 1000);
}
window.onload = function () {
init();
console.log(domPool)
// 为input和button添加事件监听
let btn = document.getElementsByTagName('button')[0];
let input = document.getElementsByTagName('input')[0];
btn.addEventListener('click', () => {
input.value = input.value.trim();
if (input.value) danmuPool.push(input.value);
})
input.addEventListener('keyup', (e) => {
if (e.key === 'Enter' && (input.value = input.value.trim())) {
danmuPool.push(input.value);
}
})
setInterval(() => {
let channel;
if(danmuPool.length && ( channel = getChannel())!= -1){
let dom = domPool[channel].shift();
let danmu = danmuPool.shift();
shootDanmu(dom, danmu, channel);
}
}, 1)
}
</script>
</body>
</html>
原生js--直播弹幕
最新推荐文章于 2022-11-28 10:48:47 发布