<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>原生JS實(shí)現(xiàn)彈幕效果</title>
<style>
#wrapper {
height: 400px;
width: 700px;
position: relative;
overflow: hidden;
background: url(http://www.drama-asia.se/wp-content/uploads/2016/06/14375197_1349947520504_800x600.jpg);
color: #ffffff82;
font-size: 14px;
text-shadow: 1px 1px #000;
}
.right {
position: absolute;
visibility: hidden;
white-space: nowrap;
/*left: 700px;*/
transform: translateX(700px);
}
.left {
position: absolute;
white-space: nowrap;
user-select: none;
transition: transform 7s linear; /* 時(shí)間相同 越長(zhǎng)的彈幕滑動(dòng)距離越長(zhǎng) 所以越快~ */
}
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>發(fā) 送</button>
</div>
<script>
/**
* 設(shè)置 彈幕DOM池 每一個(gè)通道最多六條彈幕
**/
const MAX_DM_COUNT = 6;
const CHANNEL_COUNT = 10;
let domPool = [];
let danmuPool = [
'前方大量彈幕來襲,請(qǐng)做好準(zhǔn)備!', '2333333', '2333333', '2333333', '2333333', '2333333',
'潯陽江頭夜送客, 楓葉荻花秋瑟瑟', '2333333', '2333333', '2333333', '2333333', '2333333', '2333333',
'主人下馬客在船, 舉酒欲飲無管弦。', '醉不成歡慘將別, 別時(shí)茫茫江浸月', '忽聞水上琵琶聲, 主人忘歸客不發(fā)。',
'尋聲暗問彈者誰? 琵琶聲停欲語遲。', '移船相近邀相見, 添酒回?zé)糁亻_宴。', '千呼萬喚始出來, 猶抱琵琶半遮面。',
'轉(zhuǎn)軸撥弦三兩聲, 未成曲調(diào)先有情。', '弦弦掩抑聲聲思, 似訴平生不得志。', '低眉信手續(xù)續(xù)彈, 說盡心中無限事。',
'輕攏慢捻抹復(fù)挑, 初為霓裳后六幺。', '大弦嘈嘈如急雨, 小弦切切如私語。', '嘈嘈切切錯(cuò)雜彈, 大珠小珠落玉盤。',
'間關(guān)鶯語花底滑, 幽咽泉流冰下難。', '冰泉冷澀弦凝絕, 凝絕不通聲暫歇。', '別有幽愁暗恨生, 此時(shí)無聲勝有聲。',
'銀瓶乍破水漿迸, 鐵騎突出刀槍鳴。', '曲終收撥當(dāng)心畫, 四弦一聲如裂帛。', '東船西舫悄無言, 唯見江心秋月白。',
'沉吟放撥插弦中, 整頓衣裳起斂容。', '自言本是京城女, 家在蝦蟆陵下住。', '十三學(xué)得琵琶成, 名屬教坊第一部。',
'曲罷曾教善才服, 妝成每被秋娘妒。', '五陵年少爭(zhēng)纏頭, 一曲紅綃不知數(shù)。', '鈿頭銀篦擊節(jié)碎, 血色羅裙翻酒污。',
'今年歡笑復(fù)明年, 秋月春風(fēng)等閑度。', '弟走從軍阿姨死, 暮去朝來顏色故。', '門前冷落鞍馬稀, 老大嫁作商人婦。',
'商人重利輕別離, 前月浮梁買茶去。', '去來江口守空船, 繞船月明江水寒。', '夜深忽夢(mèng)少年事, 夢(mèng)啼妝淚紅闌干。',
'我聞琵琶已嘆息, 又聞此語重唧唧。', '同是天涯淪落人, 相逢何必曾相識(shí)!', '我從去年辭帝京, 謫居臥病潯陽城。',
'潯陽地僻無音樂, 終歲不聞絲竹聲。', '住近湓江地低濕, 黃蘆苦竹繞宅生。', '其間旦暮聞何物? 杜鵑啼血猿哀鳴。',
'春江花朝秋月夜, 往往取酒還獨(dú)傾。', '豈無山歌與村笛? 嘔啞嘲哳難為聽。', '今夜聞君琵琶語, 如聽仙樂耳暫明。',
'莫辭更坐彈一曲, 為君翻作《琵琶行》。', '感我此言良久立, 卻坐促弦弦轉(zhuǎn)急。', '凄凄不似向前聲, 滿座重聞皆掩泣。',
'座中泣下誰最多? 江州司馬青衫濕。'
];
let hasPosition = [];
/**
* 做一下初始化工作
*/
function init() {
let wrapper = document.getElementById('wrapper')
// 先new一些span 重復(fù)利用這些DOM
for (let j = 0; j < CHANNEL_COUNT; j++) {
let doms = [];
for (let i = 0; i < MAX_DM_COUNT; i++) {
// 要全部放進(jìn)wrapper
let dom = document.createElement('span');
wrapper.appendChild(dom);
// 初始化dom的位置 通過設(shè)置className
dom.className = 'right';
// DOM的通道是固定的 所以設(shè)置好top就不需要再改變了
dom.style.top = j * 20 + 'px';
// 放入改通道的DOM池
doms.push(dom);
// 每次到transition結(jié)束的時(shí)候 就是彈幕劃出屏幕了 將DOM位置重置 再放回DOM池
dom.addEventListener('transitionend', () => {
dom.className = 'right';
// dom.style.transition = null;
// dom.style.left = null;
dom.style.transform = null;
domPool[j].push(dom);
});
}
domPool.push(doms);
}
// hasPosition 標(biāo)記每個(gè)通道目前是否有位置
for (let i = 0; i < CHANNEL_COUNT; i++) {
hasPosition[i] = true;
}
}
/**
* 獲取一個(gè)可以發(fā)射彈幕的通道 沒有則返回-1
*/
function getChannel() {
for (let i = 0; i < CHANNEL_COUNT; i++) {
if (hasPosition[i] && domPool[i].length) return i;
}
return -1;
}
/**
* 根據(jù)DOM和彈幕信息 發(fā)射彈幕
*/
function shootDanmu(dom, text, channel) {
console.log('biu~ [' + text + ']');
dom.innerText = text;
// 如果為每個(gè)彈幕設(shè)置 transition 可以保證每個(gè)彈幕的速度相同 這里沒有保證速度相同
// dom.style.transition = `transform ${7 + dom.clientWidth / 100}s linear`;
// dom.style.left = '-' + dom.clientWidth + 'px';
// 設(shè)置彈幕的位置信息 性能優(yōu)化 left -> transform
dom.style.transform = `translateX(${-dom.clientWidth}px)`;
dom.className = 'left';
hasPosition[channel] = false;
// 彈幕全部顯示之后 才能開始下一條彈幕
// 大概 dom.clientWidth * 10 的時(shí)間 該條彈幕就從右邊全部劃出到可見區(qū)域 再加1秒保證彈幕之間距離
setTimeout(() => {
hasPosition[channel] = true;
}, dom.clientWidth * 10 + 1000);
}
window.onload = function() {
init();
// 為input和button添加事件監(jiān)聽
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);
}
})
// 每隔1ms從彈幕池里獲取彈幕(如果有的話)并發(fā)射
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彈幕
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 實(shí)現(xiàn)原理 1、設(shè)置展示彈幕元素位置屬性為relative2、動(dòng)態(tài)創(chuàng)建彈幕元素,位置屬性設(shè)置absolute,lef...
- 1.首先創(chuàng)建彈幕框架 實(shí)現(xiàn)彈幕輸入和顯示 2.js實(shí)現(xiàn)輸出
- var hasLastCheckReturned = true; var lastCheckedTime = 0;...
- 原生js實(shí)現(xiàn)彈幕效果原理 二 距離寫實(shí)現(xiàn)原理一有很長(zhǎng)一段時(shí)間了,因?yàn)楹孟駴]什么人看,所以我就不太想寫原理二,為了不...