全站通知:
Widget:Danmu
刷
历
编
跳到导航
跳到搜索
<!DOCTYPE html> <html>
<head>
<meta charset="UTF-8">
<title>弹幕效果</title>
<style>
.danmu-container {
width: 100%;
position: relative;
overflow: hidden;
}
.danmu {
position: absolute;
color: #383030;
white-space: nowrap;
font-size: 16px;
top: 0;
left: 100%;
}
@keyframes moveLeft {
from {
transform: translateX(0);
}
to {
transform: translateX(-100vw);
}
}
</style>
</head>
<body>
<script>
const config = {
duration: 8,
minInterval: 300,
maxInterval: 800,
maxDanmu: 20,
containerHeight: '200px',
trackHeight: 20,
trackPadding: 2,
fontSize: 20,
cleanupInterval: 2000,
defaultDanmu: [
'欢迎来到弹幕区~',
'下次赶晚的猎人小姐:我再也不早早下池了[跪了][跪了][跪了][跪了]',
'猎人小姐:老姚烧烤再送20[开学季][开学季][开学季]',
"猎人小姐:真的送啦!!!!",
"恋与深空:感谢支持,20连福利大派送!",
"猎人小姐:可以啊啊啊我爱你",
"!!:???好家伙",
"啊啊啊好好好稳稳稳",
"爽!哈哈哈哈哈",
"在【首页:他】的评论区留言即可发送弹幕~"
]
};
class TrackManager {
constructor(containerHeight, trackHeight, trackPadding) {
this.trackHeight = trackHeight;
this.trackPadding = trackPadding;
this.numTracks = Math.floor(containerHeight / (trackHeight));
console.log(`Container height: ${containerHeight}, Tracks: ${this.numTracks}`);
this.tracks = new Array(this.numTracks).fill(false);
}
getAvailableTrack() {
const availableTracks = this.tracks
.map((occupied, index) => ({ occupied, index }))
.filter(track => !track.occupied)
.map(track => track.index);
if (availableTracks.length === 0) return -1;
const randomIndex = Math.floor(Math.random() * availableTracks.length);
return availableTracks[randomIndex];
}
occupyTrack(trackIndex) {
if (trackIndex >= 0 && trackIndex < this.tracks.length) {
this.tracks[trackIndex] = true;
}
}
releaseTrack(trackIndex) {
if (trackIndex >= 0 && trackIndex < this.tracks.length) {
this.tracks[trackIndex] = false;
}
}
}
const trackManager = new TrackManager(
parseInt(config.containerHeight),
config.trackHeight,
config.trackPadding
);
let danmuArr = [...config.defaultDanmu];
function getDanmuFromComments() {
const comments = document.querySelectorAll('.comment-thread');
comments.forEach(comment => {
try {
const username = comment.querySelector('.comment-user-name a')?.textContent;
const content = comment.querySelector('.comment-text')?.textContent;
if (username && content) {
const danmuText = `${username}:${content}`;
danmuArr.push(danmuText);
}
} catch (error) {
console.error('Error processing comment:', error);
}
});
}
const container = document.getElementById('danmuContainer');
container.style.height = config.containerHeight;
let activeDanmu = 0;
const danmuPool = [];
function createDanmuPool(size) {
for (let i = 0; i < size; i++) {
const danmu = document.createElement('div');
danmu.className = 'danmu';
danmu.style.display = 'none';
container.appendChild(danmu);
danmuPool.push(danmu);
}
}
function getDanmuFromPool() {
return danmuPool.find(danmu => danmu.style.display === 'none') || null;
}
function createDanmu(text) {
if (activeDanmu >= config.maxDanmu) return;
const trackIndex = trackManager.getAvailableTrack();
if (trackIndex === -1) return;
const danmu = getDanmuFromPool();
if (!danmu) return;
activeDanmu++;
trackManager.occupyTrack(trackIndex);
danmu.innerText = text;
danmu.style.display = 'block';
danmu.style.top = (trackIndex * (config.trackHeight + config.trackPadding)) + 'px';
danmu.style.animation = `moveLeft ${config.duration}s linear`;
danmu.dataset.trackIndex = trackIndex;
danmu.addEventListener('animationend', () => {
danmu.style.display = 'none';
danmu.style.animation = ;
activeDanmu--;
trackManager.releaseTrack(parseInt(danmu.dataset.trackIndex));
}, { once: true });
}
let lastTime = 0;
let nextInterval = config.minInterval;
function animate(currentTime) {
if (!lastTime) lastTime = currentTime;
const elapsed = currentTime - lastTime;
if (elapsed >= nextInterval) {
const randomDelay = Math.random() * 500;
setTimeout(() => {
const randomIndex = Math.floor(Math.random() * danmuArr.length);
createDanmu(danmuArr[randomIndex]);
}, randomDelay);
lastTime = currentTime;
nextInterval = Math.random() * (config.maxInterval - config.minInterval) + config.minInterval;
}
requestAnimationFrame(animate);
}
async function initialize() {
try {
createDanmuPool(config.maxDanmu);
requestAnimationFrame(animate);
const hasComments = await waitForComments();
if (hasComments) {
getDanmuFromComments();
} else {
console.log('Comments not found, using default danmu only');
danmuArr = [...config.defaultDanmu];
}
} catch (error) {
console.error('Initialization error:', error);
danmuArr = [...config.defaultDanmu];
createDanmuPool(config.maxDanmu);
requestAnimationFrame(animate);
}
}
function waitForComments() {
return new Promise((resolve) => {
let attempts = 0;
const maxAttempts = 50;
const checkComments = () => {
attempts++;
const comments = document.querySelectorAll('.comment-thread');
if (comments.length > 0) {
resolve(true);
} else if (attempts >= maxAttempts) {
resolve(false);
} else {
setTimeout(checkComments, 100);
}
};
checkComments();
});
}
initialize();
setInterval(() => {
danmuPool.forEach(danmu => {
if (danmu.style.display === 'none') {
danmu.style.animation = ;
}
});
}, config.cleanupInterval);
</script>
</body>
</html>

沪公网安备 31011002002714 号