《Beyond - 午夜怨曲》相关说明
<style>.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<h2>JS资源代码</h2>
<div class='mum'>
<div class="tGreen"><cl-cd data-idx="1">/* tube3dlrc.js (MaHeihei 2024-6-10)</cl-cd>
<cl-cd data-idx="2"> 约定:</cl-cd>
<cl-cd data-idx="3"> ① 帖子 <span class="tRed">id</span>=<span class="tMagenta">"tz"</span></cl-cd>
<cl-cd data-idx="4"> ② audio <span class="tRed">id</span>=<span class="tMagenta">"aud"</span></cl-cd>
<cl-cd data-idx="5"> ③ video class=<span class="tMagenta">"vid"</span></cl-cd>
<cl-cd data-idx="6"> ④ 播放控制器标签 <span class="tRed">id</span>=<span class="tMagenta">"player"</span></cl-cd>
<cl-cd data-idx="7"> ⑤ 歌词显示标签 <span class="tRed">id</span>=<span class="tMagenta">"lrc"</span></cl-cd>
<cl-cd data-idx="8"> ⑥ 歌词数组 <span class="tBlue">var</span> lrcAr = [,,3,,];</cl-cd>
<cl-cd data-idx="9"> 注意:</cl-cd>
<cl-cd data-idx="10"> 脚本通过管理CSS变量 --prg 渲染播放进度、--state 控制按钮及其他可能存在的CSS动画;对lrc歌词的管理,仅负责呈现歌词,歌词动画由帖子完成。</cl-cd>
<cl-cd data-idx="11">*/</cl-cd></div>
<cl-cd data-idx="12"> </cl-cd>
<cl-cd data-idx="13">(<span class="tBlue">function</span>() {</cl-cd>
<div class="tGreen"><cl-cd data-idx="14"> /* 声明变量</cl-cd>
<cl-cd data-idx="15"> vids : 视频标签</cl-cd>
<cl-cd data-idx="16"> btnSize : 按钮尺寸</cl-cd>
<cl-cd data-idx="17"> keynow : 当前歌词索引</cl-cd>
<cl-cd data-idx="18"> */</cl-cd></div>
<cl-cd data-idx="19"> <span class="tBlue">var</span> vids = <span class="tRed">document</span>.querySelectorAll(<span class="tMagenta">'.vid'</span>),</cl-cd>
<cl-cd data-idx="20"> btnSize = parseInt(<span class="tRed">window</span>.getComputedStyle(player).getPropertyValue(<span class="tMagenta">'--btnSize'</span>)),</cl-cd>
<cl-cd data-idx="21"> keynow = 0;</cl-cd>
<cl-cd data-idx="22"> </cl-cd>
<cl-cd data-idx="23"> <span class="tGreen">//工具函数 : 秒→分</span></cl-cd>
<cl-cd data-idx="24"> <span class="tBlue">var</span> s2m = (s) => (<span class="tRed">Math</span>.floor(s / 60)).toString().padStart(2, <span class="tMagenta">'0'</span>) + <span class="tMagenta">':'</span> + (<span class="tRed">Math</span>.floor(s % 60)).toString().padStart(2, <span class="tMagenta">'0'</span>);</cl-cd>
<cl-cd data-idx="25"> </cl-cd>
<cl-cd data-idx="26"> <span class="tGreen">//联动函数 : 通过音频暂停状态管理关键帧动画与视频</span></cl-cd>
<cl-cd data-idx="27"> <span class="tBlue">var</span> mState = () => {</cl-cd>
<cl-cd data-idx="28"> tz.style.setProperty(<span class="tMagenta">'--state'</span>,[<span class="tMagenta">'running'</span>,<span class="tMagenta">'paused'</span>][+aud.paused]);</cl-cd>
<cl-cd data-idx="29"> <span class="tBlue">if</span>(vids.length > 0) vids.forEach(vid => aud.paused ? vid.pause() : vid.play());</cl-cd>
<cl-cd data-idx="30"> };</cl-cd>
<cl-cd data-idx="31"> </cl-cd>
<cl-cd data-idx="32"> <span class="tGreen">//歌词索引变更函数 : 正常播放状态下自然递增</span></cl-cd>
<cl-cd data-idx="33"> <span class="tBlue">var</span> addkey = () => {</cl-cd>
<cl-cd data-idx="34"> <span class="tBlue">if</span>(keynow > lrcAr.length - 1) <span class="tBlue">return</span>;</cl-cd>
<cl-cd data-idx="35"> <span class="tBlue">for</span>(<span class="tBlue">var</span> k = 0; k < lrcAr.length; k ++) {</cl-cd>
<cl-cd data-idx="36"> <span class="tBlue">if</span>(aud.currentTime > lrcAr) {</cl-cd>
<cl-cd data-idx="37"> showLrc(keynow);</cl-cd>
<cl-cd data-idx="38"> keynow ++;</cl-cd>
<cl-cd data-idx="39"> <span class="tBlue">break</span>;</cl-cd>
<cl-cd data-idx="40"> }</cl-cd>
<cl-cd data-idx="41"> }</cl-cd>
<cl-cd data-idx="42"> };</cl-cd>
<cl-cd data-idx="43"> </cl-cd>
<cl-cd data-idx="44"> <span class="tGreen">//显示歌词函数</span></cl-cd>
<cl-cd data-idx="45"> <span class="tBlue">var</span> showLrc = (key) => lrc.innerText = lrcAr;</cl-cd>
<cl-cd data-idx="46"> </cl-cd>
<cl-cd data-idx="47"> <span class="tGreen">//监听audio控件播放和暂停事件 : 运行联动函数</span></cl-cd>
<cl-cd data-idx="48"> aud.onplaying = aud.onpause = () => mState();</cl-cd>
<cl-cd data-idx="49"> </cl-cd>
<cl-cd data-idx="50"> <span class="tGreen">//监听audio控件播放时间变化事件 : 驱动进度、播放时间信息、歌词索引的变化</span></cl-cd>
<cl-cd data-idx="51"> aud.ontimeupdate = () => {</cl-cd>
<cl-cd data-idx="52"> player.style.setProperty(<span class="tMagenta">'--prg'</span>, (aud.currentTime / aud.duration * 100 || 0) + <span class="tMagenta">'%'</span>);</cl-cd>
<cl-cd data-idx="53"> player.dataset.time = s2m(aud.currentTime) + <span class="tMagenta">' '</span> + s2m(aud.duration);</cl-cd>
<cl-cd data-idx="54"> addkey();</cl-cd>
<cl-cd data-idx="55"> };</cl-cd>
<cl-cd data-idx="56"> </cl-cd>
<cl-cd data-idx="57"> <span class="tGreen">//监听audio控件寻轨事件 : 重新计算歌词索引</span></cl-cd>
<cl-cd data-idx="58"> aud.onseeked = () => {</cl-cd>
<cl-cd data-idx="59"> <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j < lrcAr.length; j ++) {</cl-cd>
<cl-cd data-idx="60"> <span class="tBlue">if</span>(aud.currentTime < lrcAr) {</cl-cd>
<cl-cd data-idx="61"> keynow = j - 1;</cl-cd>
<cl-cd data-idx="62"> <span class="tBlue">if</span>(keynow < 0) keynow = 0;</cl-cd>
<cl-cd data-idx="63"> showLrc(keynow);</cl-cd>
<cl-cd data-idx="64"> <span class="tBlue">break</span>;</cl-cd>
<cl-cd data-idx="65"> }</cl-cd>
<cl-cd data-idx="66"> }</cl-cd>
<cl-cd data-idx="67"> };</cl-cd>
<cl-cd data-idx="68"> </cl-cd>
<cl-cd data-idx="69"> <span class="tGreen">//播放控制器点击事件 : 依据点击范围处理音频进度改变、播放暂停等事宜</span></cl-cd>
<cl-cd data-idx="70"> player.onclick = (e) => {</cl-cd>
<cl-cd data-idx="71"> <span class="tBlue">if</span>(e.offsetY > 0) aud.currentTime = aud.duration * e.offsetX / player.offsetWidth;</cl-cd>
<cl-cd data-idx="72"> <span class="tBlue">if</span>(e.offsetY < 0 && e.offsetX > player.offsetWidth / 2 - btnSize / 2 && e.offsetX < player.offsetWidth / 2 + btnSize / 2) aud.paused ? aud.play() : aud.pause();</cl-cd>
<cl-cd data-idx="73"> };</cl-cd>
<cl-cd data-idx="74"> </cl-cd>
<cl-cd data-idx="75"> <span class="tGreen">//鼠标指针经过播放控制器事件 : 根据指针位置提供友好交互</span></cl-cd>
<cl-cd data-idx="76"> player.onmousemove = (e) => {</cl-cd>
<cl-cd data-idx="77"> <span class="tBlue">if</span>(e.offsetY < 0) {</cl-cd>
<cl-cd data-idx="78"> <span class="tBlue">if</span>(e.offsetX > player.offsetWidth / 2 - btnSize / 2 && e.offsetX < player.offsetWidth / 2 + btnSize / 2) {</cl-cd>
<cl-cd data-idx="79"> player.title = aud.paused ? <span class="tMagenta">'播放'</span> : <span class="tMagenta">'暂停'</span>;</cl-cd>
<cl-cd data-idx="80"> player.style.cursor = <span class="tMagenta">'pointer'</span>;</cl-cd>
<cl-cd data-idx="81"> }</cl-cd>
<cl-cd data-idx="82"> }<span class="tBlue">else</span>{</cl-cd>
<cl-cd data-idx="83"> player.title = <span class="tMagenta">'调节进度'</span>;</cl-cd>
<cl-cd data-idx="84"> player.style.cursor = <span class="tMagenta">'pointer'</span>;</cl-cd>
<cl-cd data-idx="85"> }</cl-cd>
<cl-cd data-idx="86"> };</cl-cd>
<cl-cd data-idx="87">})();</cl-cd>
</div>
本帖最后由 马黑黑 于 2024-6-11 12:08 编辑
将代码存为JS文档,然后在帖子中按约定引用资源,JS即可渲染出相应效果:
帖子HTML基本结构:
<div id="tz">
<audio id="aud" src="音频地址" autoplay loop></audio>
<div id="lrc">HUA CHAO PLAYER</div>
<div id="player"></div>
</div>
配套CSS(更多内容请参阅实例代码):
#lrc { position: absolute; left: 200px; top: 20px; font: normal 30px sans-serif; text-shadow: 1px 1px 1px gray; background: linear-gradient(to right, red, blue,green, red); background-clip: text; -webkit-background-clip: text; color: transparent; filter: drop-shadow(-1px -1px 6px gray); animation: swear 6s linear infinite alternate; }
#player { position: absolute; left: calc(50% - 140px); bottom: 20px; width: 280px; height:10px; background: linear-gradient(to right, var(--color) var(--prg), transparent 0); border: 1px solid var(--color); border-radius: 6px; display: grid; place-items: center; --color: purple; --prg: 0%; --btnSize: 50px;}
#player::before, #player::after { position: absolute; content: ''; }
#player::before { width: var(--btnSize); height: var(--btnSize); top: calc(var(--btnSize) * -1 - 5px); background: url('https://638183.freep.cn/638183/t23/btn/f5.png') no-repeat center/cover; animation: rot 6s linear infinite var(--state);}
#player::after { content: attr(data-time); inset: -30px 0 10px 0; text-align: justify; text-align-last: justify; font-size: 14px; color: var(--color); pointer-events: none; }
@keyframes rot { to { transform: rotate(360deg); } }
@keyframes swear {
from { transform: perspective(400px) rotateY(20deg); }
to { transform: perspective(400px) rotateY(-20deg); }
}
一楼的JS代码,只是独立出来的资源,帖子必要的CSS和HTML是不能在帖子中省略的,播放器、歌词显示等单元的构造有帖子完成。
实例地址:
Beyond - 午夜怨曲 - 音乐沙龙 - 花潮论坛 - Powered by Discuz! (huachaowang.com)
{:4_199:}这是在教怎么打包成JS?我的天,烧脑 第一次看到JS文件这样详细的讲解说明。。{:4_173:}这个真是太好了。。 南无月 发表于 2024-6-11 12:25
第一次看到JS文件这样详细的讲解说明。。这个真是太好了。。
提供给童鞋们了解一下下,有能力的可以根据需要自己修改 南无月 发表于 2024-6-11 12:18
这是在教怎么打包成JS?我的天,烧脑
和保存一个WPS文档一样简单 存文件没问题,问题是要存在一个采用 https协议的网站(空间),这样的地方不好找。 起个网名好难 发表于 2024-6-11 12:53
存文件没问题,问题是要存在一个采用 https协议的网站(空间),这样的地方不好找。
屋舍试试,永不删除 马黑黑 发表于 2024-6-11 13:02
屋舍试试,永不删除
屋舍不稳定,时不时连不上 起个网名好难 发表于 2024-6-11 14:18
屋舍不稳定,时不时连不上
境外空间,国内不同的线路连接效果确实不太一样 马黑黑 发表于 2024-6-11 15:07
境外空间,国内不同的线路连接效果确实不太一样
只能是可用但不好用(不理想) 起个网名好难 发表于 2024-6-11 15:14
只能是可用但不好用(不理想)
小文件没问题,大点的文件有时候缓冲几次才行 马黑黑 发表于 2024-6-11 15:16
小文件没问题,大点的文件有时候缓冲几次才行
大小不是多大的问题,再说 .css / .js/ .html 能有多大。 这个把JS里的内容讲得如此详细,真的太好了{:4_199:}
学习再学习{:4_199:} 又跑回去看了看帖子,css里也有很多可调的,真好{:4_187:} 二边看来开去的二次,感觉还是模糊,只是感觉js css真的很强大,会点基础还真的没有用,得深入学习才可以自由运用 小辣椒 发表于 2024-6-11 16:45
二边看来开去的二次,感觉还是模糊,只是感觉js css真的很强大,会点基础还真的没有用,得深入学习才可以自 ...
知识越全面越好 红影 发表于 2024-6-11 15:57
又跑回去看了看帖子,css里也有很多可调的,真好
该有的都有 红影 发表于 2024-6-11 15:50
这个把JS里的内容讲得如此详细,真的太好了
学习再学习
代码也不算太多,复杂度也不高