bugfix250107.1
全站通知:

Widget:Danmu

来自恋与深空WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

<!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>