返回列表 发布新帖
查看: 224|回复: 0

[代码技巧] 子比主题 – 左下角胶囊音乐样式代码

[复制链接]
SunJu_FaceMall
社区贡献

318

主题

191

回帖

1万

积分

等级头衔
Icon组别 : 管理员
Icon等级 :

积分成就
   钻石 : 0 颗
   贡献 : 35308 点
   金币 : 92 枚
Icon在线时间 : 1408 小时
Icon注册时间 : 2024-11-22
Icon最后登录 : 2026-5-11

荣誉勋章

连签LV.1会员LV.1会员LV.2会员LV.3会员LV.4会员LV.5会员LV.6会员LV.7会员LV.8会员LV.9会员LV.10

实力殿堂·绝代收藏家

飞流名人堂成员 1 FLLTCN 实名认证 特邀大神认证 诚信商家认证 信誉担保认证 精华作者+认证 飞流官方团队 vip vip-year 发表于 2025-10-10 17:40:19 | 查看全部 |阅读模式 浙江金华

交易无需等待,成交就是现在,全面资源整合网络大咖云集,让你轻松玩转互联网!

您需要 登录 才可以下载或查看,没有账号?立即注册

×
腾飞博客给大家写了一款仿张洪博客的胶囊音乐样式,我觉得这个还是不错的,一开始腾飞想写插件,发现插件有点卡,为了不影响速度直接用代码实现,这个算半成品,也算已经写好了,都可以用,话不多说喜欢的自行部署吧!

image.webp
当鼠标点了胶囊就有一个效果横向弹出来,然后播放音乐,当点了之后就收缩就自动停止音乐,模仿了张洪博客的样式,一开始写的是根据封面颜色,发现跨域问题,但是这个写插件可以解决,插件虽然写好了但是删掉了,因为太卡了,所以就代码分享吧,有技术的可以二开一下!

代码部署


将下面的代码放到:子比主题–>>自定义底部HTML代码,全部代码直接丢里面就可以!
  1. <style>
  2. :root{--player-height:44px;--capsule-radius:22px;--album-size:32px;--album-gap:9px;--lyrics-max-width:150px;--lyric-padding-right:12px;--main-bg:rgba(60,66,64,0.97);--main-bg2:rgba(70,74,80,0.98)}body{min-height:100vh;background:#f8f8f9}.tengfei-player-container{position:fixed;left:32px;bottom:40px;z-index:1000;min-width:166px;max-width:420px;width:340px;height:var(--player-height);border-radius:var(--capsule-radius);box-shadow:0 2px 9px rgba(0,0,0,0.18);background:linear-gradient(120deg,var(--main-bg) 88%,var(--main-bg2) 100%);display:flex;align-items:center;padding:0 10px;cursor:pointer;transition:width 0.6s cubic-bezier(.51,.33,.38,1.14),max-width 0.6s cubic-bezier(.51,.33,.38,1.14),min-width 0.6s cubic-bezier(.51,.33,.38,1.14),box-shadow 0.18s,background 0.8s;overflow:visible}@media (max-width:700px){.tengfei-player-container{display:none !important}}.tengfei-player-container.collapsed{width:auto !important;min-width:120px;max-width:280px;transition:width 0.5s cubic-bezier(.42,0,.11,1.05),max-width 0.29s cubic-bezier(.42,0,.11,1.05),min-width 0.22s cubic-bezier(.42,0,.11,1.05)}.song-title-area{display:flex;align-items:center;min-width:0;transition:opacity 0.39s cubic-bezier(.42,0,.11,1.05)}.tengfei-album-cover{width:var(--album-size);height:var(--album-size);object-fit:cover;border-radius:50%;margin-right:var(--album-gap);border:2px solid rgba(255,255,255,0.81);box-shadow:0 1px 4px rgba(0,0,0,0.09);flex-shrink:0;transition:box-shadow 0.25s,opacity 0.39s cubic-bezier(.42,0,.11,1.05)}.tengfei-song-title{color:white;font-size:13px;font-weight:500;min-width:34px;max-width:118px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:max-width .19s cubic-bezier(.42,0,.11,1.05),font-size .14s cubic-bezier(.42,0,.11,1.05),opacity 0.34s cubic-bezier(.42,0,.11,1.05);cursor:pointer;padding-right:2px;flex-shrink:2;display:inline-block}.center-lyric-area{flex-shrink:1;flex-grow:1;min-width:0;max-width:78vw;height:100%;display:flex;align-items:center;justify-content:center;position:relative;margin-left:16px;transition:margin-left 0.32s cubic-bezier(.42,0,.11,1.05),opacity 0.38s cubic-bezier(.42,0,.11,1.05);opacity:1}.lyrics-container{max-width:var(--lyrics-max-width);width:auto;white-space:nowrap;overflow:hidden;color:#fff;text-align:left;font-size:11.3px;font-weight:bold;letter-spacing:0.07em;line-height:1;pointer-events:none;position:relative;padding-right:var(--lyric-padding-right);text-overflow:ellipsis;flex:1 1 0;z-index:2;transition:max-width 0.38s cubic-bezier(.42,0,.11,1.05),font-size .14s cubic-bezier(.42,0,.11,1.05),opacity 0.5s cubic-bezier(.42,0,.11,1.05);background:none;opacity:1}.lyrics-line{display:block;opacity:1;pointer-events:none;transition:opacity 0.34s cubic-bezier(.5,.7,.7,1),color .17s,font-size .11s}.lyrics-current{color:#fff}.lyrics-next{color:rgba(255,255,255,0.29);font-size:9.5px}.lyrics-capsule-mask{position:absolute;top:0;bottom:0;right:0;pointer-events:none;border-radius:0 var(--capsule-radius) var(--capsule-radius) 0;background:linear-gradient(to left,rgba(183,182,182,0.65) 78%,transparent 100%);backdrop-filter:none;-webkit-backdrop-filter:none;opacity:0;z-index:13;transition:opacity 0.25s cubic-bezier(.42,0,.11,1.05),left 0.2s cubic-bezier(.42,0,.11,1.05)}.tengfei-player-container:not(.collapsed):hover .lyrics-capsule-mask{opacity:1}.controls{position:absolute;top:0;right:0px;height:var(--player-height);display:flex;align-items:center;gap:5px;z-index:16;padding-right:10px;pointer-events:none;opacity:1;transition:opacity 0.39s cubic-bezier(.42,0,.11,1.05)}.control-btn{background:rgba(255,255,255,0.09);border:none;color:white;cursor:pointer;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background-color .18s cubic-bezier(.42,0,.11,1.05),box-shadow .22s cubic-bezier(.42,0,.11,1.05),opacity .13s cubic-bezier(.42,0,.11,1.05),transform 0.32s cubic-bezier(.42,0,.11,1.05);opacity:.95;pointer-events:auto;box-shadow:0 1px 5px rgba(0,0,0,0.07);outline:none;border:0.1px solid rgba(225,225,225,0.09);font-size:0}.control-btn svg{display:block;width:21px;height:21px;pointer-events:none;transition:filter 0.13s,transform 0.13s;filter:drop-shadow(0 0 2px rgba(51,120,235,0.10));stroke:#fff}.control-btn:hover{background:rgba(255,255,255,0.19)}.control-btn:hover svg{filter:drop-shadow(0 0 5px #99c2ff60);transform:scale(1.14);stroke:#3caae7}.tengfei-player-container:not(:hover):not(.collapsed) .control-btn{opacity:0 !important;pointer-events:none;transform:scale(.89)}.tengfei-player-container:not(.collapsed):hover .control-btn{opacity:1 !important;pointer-events:auto;transform:scale(1)}.tengfei-player-container.collapsed .center-lyric-area,.tengfei-player-container.collapsed .controls,.tengfei-player-container.collapsed .lyrics-capsule-mask{opacity:0 !important;pointer-events:none !important;width:0 !important;margin:0 !important;display:none !important;transition:opacity 0.38s cubic-bezier(.42,0,.11,1.05)}.tengfei-player-container:not(.collapsed) .center-lyric-area,.tengfei-player-container:not(.collapsed) .controls{opacity:1;pointer-events:auto;display:flex !important;transition:opacity 0.38s cubic-bezier(.42,0,.11,1.05)}
  3. </style>
  4. </head>
  5. <body>
  6. <div class="tengfei-player-container collapsed" id="tengfeiMusicPlayer">
  7.   <div class="song-title-area">
  8.     <img class="tengfei-album-cover" src="" alt="专辑封面" id="tengfeiCoverClick">
  9.     <div class="tengfei-song-title" id="tengfeiTitleClick">正在加载...</div>
  10.   </div>
  11.   <div class="center-lyric-area">
  12.     <div class="lyrics-container" id="tengfeiLyricsScroll"></div>
  13.     <div class="lyrics-capsule-mask"></div>
  14.     <div class="controls">
  15.       <button class="control-btn prev" id="tengfeiPrevBtn" title="上一首">
  16.         <svg viewBox="0 0 32 32" fill="none">
  17.           <g>
  18.             <rect x="7.5" y="9.5" rx="1.2" width="2.2" height="13" fill="none" stroke="currentColor" stroke-width="1.45"/>
  19.             <polygon points="22.3,8.5 13,16 22.3,23.5" fill="none" stroke="currentColor" stroke-width="2.65" stroke-linecap="round" stroke-linejoin="round"/>
  20.           </g>
  21.         </svg>
  22.       </button>
  23.       <button class="control-btn play-pause" id="tengfeiPlayPauseBtn" title="播放/暂停">
  24.         <svg id="tengfeiPlayIconSvg" viewBox="0 0 32 32" fill="none">
  25.           <g id="tengfeiPlaySvgIcon">
  26.             <polygon points="13.6,9.6 13.6,22.4 23,16" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
  27.           </g>
  28.         </svg>
  29.       </button>
  30.       <button class="control-btn next" id="tengfeiNextBtn" title="下一首">
  31.         <svg viewBox="0 0 32 32" fill="none">
  32.           <g>
  33.             <rect x="22.3" y="9.5" rx="1.2" width="2.2" height="13" fill="none" stroke="currentColor" stroke-width="1.45"/>
  34.             <polygon points="9.7,8.5 19,16 9.7,23.5" fill="none" stroke="currentColor" stroke-width="2.65" stroke-linecap="round" stroke-linejoin="round"/>
  35.           </g>
  36.         </svg>
  37.       </button>
  38.     </div>
  39.   </div>
  40. </div>
  41. <script src="https://cdn.jsdelivr.net/npm/tinycolor2@1.6.0/dist/tinycolor-min.js"></script>
  42. <script>
  43. (function() {
  44.   function setPauseIcon(isPause){
  45.     const svg = document.getElementById('tengfeiPlayIconSvg');
  46.     if(isPause){
  47.       svg.innerHTML = '<g id="tengfeiPlaySvgIcon">' +
  48.         '<rect x="12.2" y="10.2" rx="1.05" width="3.2" height="11.6" fill="none" stroke="currentColor" stroke-width="2.1"/>' +
  49.         '<rect x="17.0" y="10.2" rx="1.05" width="3.2" height="11.6" fill="none" stroke="currentColor" stroke-width="2.1"/>' +
  50.         '</g>';
  51.     }else{
  52.       svg.innerHTML = '<g id="tengfeiPlaySvgIcon">' +
  53.         '<polygon points="13.6,9.6 13.6,22.4 23,16" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>' +
  54.         '</g>';
  55.     }
  56.   }
  57.   const playerState = {
  58.     playlist: [],
  59.     currentIndex: 0,
  60.     isPlaying: false,
  61.     lyrics: [],
  62.     currentLyricIndex: 0,
  63.     lyricOffset: 0,
  64.     collapsed: true
  65.   };
  66.   const elements = {
  67.     playerContainer: document.getElementById('tengfeiMusicPlayer'),
  68.     albumCover: document.querySelector('.tengfei-album-cover'),
  69.     songTitle: document.querySelector('.tengfei-song-title'),
  70.     playPauseBtn: document.getElementById('tengfeiPlayPauseBtn'),
  71.     prevBtn: document.getElementById('tengfeiPrevBtn'),
  72.     nextBtn: document.getElementById('tengfeiNextBtn'),
  73.     lyricsScroll: document.getElementById('tengfeiLyricsScroll'),
  74.     controls: document.querySelector('.controls'),
  75.     songTitleArea: document.querySelector('.song-title-area'),
  76.     lyricArea: document.querySelector('.center-lyric-area'),
  77.     lyricsMask: document.querySelector('.lyrics-capsule-mask'),
  78.     playIconSvg: document.getElementById('tengfeiPlayIconSvg')
  79.   };
  80.   const audio = new Audio();

  81.   function calcCapsuleMask() {
  82.     if(playerState.collapsed) return;
  83.     const lyricRect = elements.lyricsScroll.getBoundingClientRect();
  84.     const parentRect = elements.lyricArea.getBoundingClientRect();
  85.     let left = lyricRect.right - parentRect.left; // 歌词区右边到父级左边
  86.     elements.lyricsMask.style.left = left + 'px';
  87.     elements.lyricsMask.style.right = '0';
  88.     elements.lyricsMask.style.top = '0';
  89.     elements.lyricsMask.style.bottom = '0';
  90.   }
  91.   function triggerMaskUpdate() {
  92.     setTimeout(calcCapsuleMask, 1);
  93.   }
  94.   window.addEventListener('resize', triggerMaskUpdate);

  95.   function setGradientBackground(coverUrl) {
  96.     elements.albumCover.src = coverUrl || "https://via.placeholder.com/40/47484c/fff?text=音乐";
  97.     elements.albumCover.onerror = () => {
  98.       elements.albumCover.src="https://via.placeholder.com/40/47484c/fff?text=音乐";
  99.       elements.playerContainer.style.background="rgba(60,66,64,0.93)";
  100.     }
  101.     const img = new Image();
  102.     img.crossOrigin="Anonymous";
  103.     img.src=coverUrl;
  104.     img.onload = () => {
  105.       try {
  106.         const canvas = document.createElement('canvas');
  107.         canvas.width = 10; canvas.height = 10;
  108.         const ctx = canvas.getContext('2d');
  109.         ctx.drawImage(img, 0, 0, 10, 10);
  110.         const data = ctx.getImageData(0,0,10,10).data;
  111.         let r=0,g=0,b=0,count=0;
  112.         for (let i=0;i<data.length;i+=4) { r+=data[i]; g+=data[i+1]; b+=data[i+2]; count++; }
  113.         r=Math.floor(r/count); g=Math.floor(g/count); b=Math.floor(b/count);
  114.         let mainColor = tinycolor({ r,g,b });
  115.         if(mainColor.getBrightness()<60) mainColor=mainColor.lighten(20);
  116.         if(mainColor.getBrightness()>230) mainColor=mainColor.darken(12);
  117.         const dark = tinycolor(mainColor).darken(13).setAlpha(0.93).toRgbString();
  118.         const light = tinycolor(mainColor).lighten(3).setAlpha(0.90).toRgbString();
  119.         elements.playerContainer.style.transition="background 0.8s";
  120.         elements.playerContainer.style.background=`linear-gradient(135deg,${light},${dark} 95%)`;
  121.       } catch(e){
  122.         elements.playerContainer.style.background="rgba(60,66,64,0.93)";
  123.       }
  124.     }
  125.   }
  126.   async function fetchPlaylist() {
  127.     try {
  128.       const res = await fetch('https://music.3e0.cn/?server=tencent&type=playlist&id=3771408184');
  129.       const playlist = await res.json();
  130.       if(Array.isArray(playlist)&&playlist.length>0) {
  131.         playerState.playlist = playlist;
  132.         loadSong(0);
  133.       }
  134.       else elements.songTitle.textContent = '获取播放列表失败';
  135.     } catch(e){
  136.       elements.songTitle.textContent = '获取播放列表出错';
  137.     }
  138.   }
  139.   function loadSong(index) {
  140.     if(index < 0 || index >= playerState.playlist.length) return;
  141.     const song = playerState.playlist[index];
  142.     playerState.currentIndex = index;
  143.     elements.songTitle.textContent = song.name || '未知歌曲';
  144.     elements.songTitle.title = song.name || '未知歌曲';
  145.     setGradientBackground(song.pic);
  146.     audio.src = song.url || '';
  147.     audio.load();
  148.     fetchLyrics(song.lrc || song.lyricsUrl || song.lrcUrl);
  149.     setTimeout(() => {
  150.       if (playerState.collapsed) {
  151.         let titleW = getTextWidth(elements.songTitle.textContent, window.getComputedStyle(elements.songTitle));
  152.         let calcW = 32 + 9 + Math.max(titleW,40) + 2*10 + 18;
  153.         calcW = Math.max(126, Math.min(calcW, 260));
  154.         elements.playerContainer.style.width = calcW + 'px';
  155.       }
  156.       triggerMaskUpdate();
  157.     }, 50);
  158.   }
  159.   function getTextWidth(text, style) {
  160.     const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
  161.     const context = canvas.getContext("2d");
  162.     context.font = [
  163.       style.fontWeight,
  164.       style.fontSize,
  165.       style.fontFamily
  166.     ].join(' ');
  167.     return context.measureText(text).width;
  168.   }

  169.   let lyricMaxPixel = 0;
  170.   let lyricFontSize = 11.3;
  171.   let lyricGapAuto = 14;
  172.   let titleFontSize = 13;
  173.   let titleMaxWidth = 118;
  174.   let lastLyricWidth = 0;

  175.   function updateLyricLayout() {
  176.     if(playerState.collapsed) return;
  177.     if(!playerState.lyrics || playerState.lyrics.length==0) return;
  178.     let maxLyric = "";
  179.     for(const item of playerState.lyrics)
  180.       if(item.text && item.text.length > maxLyric.length) {
  181.         maxLyric = item.text;
  182.       }
  183.     let isEnglish = /[a-zA-Z]{2}/.test(maxLyric);
  184.     let lyricLen = maxLyric.length;
  185.     let fontSize = 12.4, lyricsWidth = 150;
  186.     let gap = 14;
  187.     let titleSize = 13;
  188.     let titleWidthMin = 60, titleWidthMax = 148, titleWidthBase = 120;
  189.     if(isEnglish || lyricLen > 22) {
  190.       fontSize = 10.6; lyricsWidth = 204; gap = 9; titleSize = 12.1; titleWidthBase = 92;
  191.     } else if(lyricLen > 16) {
  192.       fontSize = 11.4; lyricsWidth = 162; gap = 12; titleSize = 12.35; titleWidthBase = 105;
  193.     } else if(lyricLen > 11) {
  194.       fontSize = 12.2; lyricsWidth = 146; gap = 15; titleSize = 12.8; titleWidthBase = 115;
  195.     } else {
  196.       fontSize = 13.2; lyricsWidth = 92+lyricLen*4.5; gap = 18; titleSize = 13.1; titleWidthBase = 128;
  197.     }
  198.     lyricsWidth = Math.min(lyricsWidth, 226);
  199.     let maxW = Math.max(titleWidthMin, Math.min(titleWidthBase, 0.72*lyricsWidth));
  200.     elements.lyricsScroll.style.fontSize = fontSize + "px";
  201.     elements.lyricsScroll.style.maxWidth = lyricsWidth + "px";
  202.     lyricMaxPixel = lyricsWidth;
  203.     lyricFontSize = fontSize;
  204.     lastLyricWidth = lyricsWidth;
  205.     elements.lyricArea.style.marginLeft = gap + "px";
  206.     lyricGapAuto = gap;
  207.     titleMaxWidth = Math.max(titleWidthMin, Math.min(titleWidthMax, titleWidthBase, elements.playerContainer.clientWidth-lyricsWidth-80-32-10-10));
  208.     elements.songTitle.style.maxWidth = titleMaxWidth + "px";
  209.     elements.songTitle.style.fontSize = titleSize + "px";
  210.     titleFontSize = titleSize;
  211.     triggerMaskUpdate();
  212.   }
  213.   async function fetchLyrics(url) {
  214.     try {
  215.       if(!url){ showLyrics('暂无歌词'); triggerMaskUpdate(); return; }
  216.       const response = await fetch(url);
  217.       const text = await response.text();
  218.       parseLyrics(text);
  219.     } catch (error) {
  220.       showLyrics('歌词加载失败');
  221.       triggerMaskUpdate();
  222.     }
  223.   }
  224.   function parseLyrics(text) {
  225.     if(!text){ showLyrics('暂无歌词'); triggerMaskUpdate(); return;}
  226.     const lines = text.split('\n');
  227.     const lyrics = [];
  228.     const regexs = [
  229.       /\[(\d+):(\d+)\.(\d+)\](.*)/,
  230.       /\[(\d+):(\d+)\](.*)/
  231.     ];
  232.     for(let line of lines){
  233.       let match = line.match(regexs[0]);
  234.       if(match){
  235.         let m=parseInt(match[1]), s=parseInt(match[2]), ms=parseInt(match[3]);
  236.         let time = m*60 + s + ms/100;
  237.         let lyricText = match[4].trim();
  238.         if(lyricText) lyrics.push({time, timeEnd: time+2, text: lyricText});
  239.         continue;
  240.       }
  241.       match = line.match(regexs[1]);
  242.       if(match){
  243.         let m = parseInt(match[1]), s = parseInt(match[2]);
  244.         let time = m*60 + s;
  245.         let lyricText = match[3].trim();
  246.         if(lyricText) lyrics.push({time, timeEnd: time+2, text: lyricText});
  247.       }
  248.     }
  249.     for (let i=0;i<lyrics.length-1;i++) {
  250.       lyrics[i].timeEnd = lyrics[i+1].time-0.1;
  251.     }
  252.     playerState.lyrics = lyrics;
  253.     playerState.currentLyricIndex = 0;
  254.     updateLyricLayout();
  255.     showLyricsAnimated(0, false);
  256.     triggerMaskUpdate();
  257.   }
  258.   function showLyricsAnimated(idx, animate=true) {
  259.     const lyrics = playerState.lyrics || [];
  260.     const cur = lyrics[idx] ? lyrics[idx].text : '';
  261.     const nxt = lyrics[idx+1] ? lyrics[idx+1].text : '';
  262.     const container = elements.lyricsScroll;
  263.     container.innerHTML = '';
  264.     const lineCur = document.createElement('div');
  265.     lineCur.className = 'lyrics-line lyrics-current';
  266.     lineCur.textContent = cur || '';
  267.     lineCur.style.opacity = "1";
  268.     lineCur.style.transition = "opacity 0.34s cubic-bezier(.5,.7,.7,1)";
  269.     lineCur.style.willChange = "opacity";
  270.     lineCur.style.fontSize = lyricFontSize + "px";
  271.     const lineNxt = document.createElement('div');
  272.     lineNxt.className = 'lyrics-line lyrics-next';
  273.     lineNxt.textContent = nxt || '';
  274.     lineNxt.style.opacity = "0.45";
  275.     lineNxt.style.transition = "opacity 0.33s cubic-bezier(.54,.54,.7,1)";
  276.     lineNxt.style.willChange = "opacity";
  277.     lineNxt.style.fontSize = Math.max(9, lyricFontSize*0.77) + "px";
  278.     container.appendChild(lineCur);
  279.     container.appendChild(lineNxt);
  280.     if(animate){
  281.       lineCur.style.opacity = "0";
  282.       setTimeout(()=>{ lineCur.style.opacity="1"; }, 12);
  283.       lineNxt.style.opacity = "0.15";
  284.       setTimeout(()=>{ lineNxt.style.opacity="0.45"; }, 33);
  285.     }
  286.     triggerMaskUpdate();
  287.   }
  288.   function updateLyrics() {
  289.     if (!playerState.lyrics || playerState.lyrics.length === 0) return;
  290.     const currentTime = audio.currentTime + playerState.lyricOffset;
  291.     const lyrics = playerState.lyrics;
  292.     let newIndex = playerState.currentLyricIndex;
  293.     let found = false;
  294.     for(let i=0; i<lyrics.length; i++){
  295.       if(currentTime >= lyrics[i].time && currentTime < lyrics[i].timeEnd) {
  296.         newIndex = i; found = true; break;
  297.       }
  298.     }
  299.     if(!found && currentTime < lyrics[0].time) { newIndex = 0; }
  300.     else if(!found) { newIndex = lyrics.length-1; }
  301.     if(newIndex !== playerState.currentLyricIndex) {
  302.       showLyricsAnimated(newIndex, true);
  303.       playerState.currentLyricIndex = newIndex;
  304.     } else if(playerState.lyrics && elements.lyricsScroll.children.length===2){
  305.       let nxt = lyrics[newIndex+1] ? lyrics[newIndex+1].text : '';
  306.       elements.lyricsScroll.children[1].textContent = nxt;
  307.     }
  308.     triggerMaskUpdate();
  309.   }
  310.   function togglePlay(force) {
  311.     if(force==="play"){
  312.       audio.play().catch(()=>{});
  313.       playerState.isPlaying=true;
  314.       setPauseIcon(true);
  315.       elements.playerContainer.classList.add('playing');
  316.     }else if(force==="pause"){
  317.       audio.pause();
  318.       playerState.isPlaying=false;
  319.       setPauseIcon(false);
  320.       elements.playerContainer.classList.remove('playing');
  321.       collapsePlayer();
  322.     }else{
  323.       if(audio.paused)  togglePlay("play");
  324.       else togglePlay("pause");
  325.     }
  326.   }
  327.   function nextSong() {
  328.     let idx = (playerState.currentIndex+1)%playerState.playlist.length;
  329.     loadSong(idx); if(playerState.isPlaying) audio.play();
  330.   }
  331.   function prevSong() {
  332.     let idx = (playerState.currentIndex-1+playerState.playlist.length)%playerState.playlist.length;
  333.     loadSong(idx); if(playerState.isPlaying) audio.play();
  334.   }
  335.   elements.playPauseBtn.addEventListener('click', e=>{
  336.     e.stopPropagation(); togglePlay();
  337.   });
  338.   elements.nextBtn.addEventListener('click', e=>{
  339.     e.stopPropagation(); nextSong();
  340.   });
  341.   elements.prevBtn.addEventListener('click', e=>{
  342.     e.stopPropagation(); prevSong();
  343.   });
  344.   function collapsePlayer() {
  345.     playerState.collapsed = true;
  346.     elements.playerContainer.classList.add('collapsed');
  347.     elements.playerContainer.style.transition="width 0.59s cubic-bezier(.49,.37,.36,.97), max-width 0.36s, min-width 0.32s";
  348.     elements.playerContainer.style.width = '';
  349.     elements.songTitle.style.maxWidth = '118px';
  350.     elements.songTitle.style.fontSize = '13px';
  351.     audio.pause();
  352.     elements.lyricsScroll.style.fontSize = "11.3px";
  353.     elements.lyricsScroll.style.maxWidth = "150px";
  354.     elements.lyricArea.style.marginLeft = "14px";
  355.     setTimeout(() => {
  356.       elements.songTitleArea.style.opacity = 1;
  357.       elements.lyricArea.style.opacity = 0;
  358.       elements.lyricsScroll.style.opacity = 0;
  359.       elements.controls.style.opacity = 0;
  360.     }, 20);
  361.     elements.lyricsMask.style.width = "0px";
  362.     elements.lyricsMask.style.left = "";
  363.     elements.lyricsMask.style.opacity = "0";
  364.   }
  365.   function expandPlayer() {
  366.     playerState.collapsed = false;
  367.     elements.playerContainer.classList.remove('collapsed');
  368.     elements.playerContainer.style.transition="width 0.68s cubic-bezier(.51,.33,.38,1.18), max-width 0.45s";
  369.     elements.playerContainer.style.width = '340px';
  370.     elements.songTitleArea.style.opacity = 1;
  371.     elements.lyricArea.style.opacity = 1;
  372.     elements.lyricsScroll.style.opacity = 1;
  373.     elements.controls.style.opacity = 1;
  374.     setTimeout(()=>{togglePlay('play');},130);
  375.     setTimeout(()=>{updateLyricLayout();
  376.       elements.lyricArea.style.opacity=1;
  377.       elements.lyricsScroll.style.opacity=1;
  378.       elements.controls.style.opacity=1;
  379.       triggerMaskUpdate();
  380.     },120);
  381.   }
  382.   elements.playerContainer.addEventListener('click', function(e){
  383.     if ([elements.playPauseBtn, elements.prevBtn, elements.nextBtn,elements.playIconSvg].includes(e.target)) return;
  384.     if (playerState.collapsed) { expandPlayer(); }
  385.     else { collapsePlayer(); }
  386.   });
  387.   audio.addEventListener('timeupdate', updateLyrics);
  388.   audio.addEventListener('ended', ()=>{ nextSong(); });

  389.   fetchPlaylist();
  390.   collapsePlayer();
  391.   if(window.matchMedia('(any-pointer: coarse)').matches){
  392.     elements.prevBtn.style.display = elements.nextBtn.style.display = elements.playPauseBtn.style.display = 'none';
  393.   }

  394.   setTimeout(triggerMaskUpdate, 200);
  395. })();
  396. </script>
复制代码


【小飞侠提醒您:搜索时输入t1608代号,方便好记直达本帖!】

本帖被以下淘专辑推荐:

路虽远,行则将至;事虽难,做则必成。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

飞流广播+ 发布

系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
10-30 17:02
系统消息:柒沐已经连续答对10道难题,逆天学霸谁与争锋?!#每日答题#
10-09 09:07
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
09-24 09:00
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
09-11 11:40
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
09-02 09:17
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
08-27 08:56
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
08-20 15:12
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
08-03 10:22
系统消息:柒沐已经连续答对10道难题,逆天学霸谁与争锋?!#每日答题#
06-30 08:57
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
06-18 09:14
系统消息:清风网络已经连续答对10道难题,逆天学霸谁与争锋?!#每日答题#
04-11 09:40
系统消息:清风网络已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
04-10 09:31
系统消息:IXM77777已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
04-09 13:44
系统消息:清风网络已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
04-09 09:22
系统消息:柒沐已经连续答对10道难题,逆天学霸谁与争锋?!#每日答题#
04-09 08:52
系统消息:清风网络已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
04-08 09:24
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
04-07 09:02
系统消息:柒沐已经连续答对10道难题,逆天学霸谁与争锋?!#每日答题#
02-27 09:35
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
02-26 09:06
系统消息:柒沐已经连续答对3道难题,逆天学霸谁与争锋?!#每日答题#
02-25 08:49
站内通告

提供资源交易、信息共享、靓号交流、技术变现、学习问答、兴趣娱乐等全面服务。

1.丰富功能系统,扩展社区特色玩法,打造最好的互联网聚集圈子。

2.准确信息真实交易,安全快捷又方便,让虚拟交易面对面。

3. 天上不会掉馅饼,话术骗术迷人心,切勿脱离平台线下交易,被骗与平台无关!

4. 欺诈骗钱,违规违法将视情受到警告&禁言&封号甚至检举至👮🏻‍♀️处理!

官方Q群:钉推群:BAYR2383 站长QQ:3388700000

飞流论坛(FLLT.CN),一个专注于资源信息发布、虚拟网络交易、技术学习与娱乐社交的交流平台。
  • 钉钉新帖推送群
  • 官方交流QQ群
  • 站长唯一微信号

💥客户端|🧿小黑屋|📴手机页|飞流网 |网站地图

GMT+8, 2026-5-11 08:50 , Processed in 0.072959 second(s), 67 queries, MemCached On , Gzip On.

飞流论坛 HanAnalytics icp

Copyright © 2024-2026 飞流网 版权所有 All Rights Reserved. X3.5

快速回复 返回顶部 返回列表