又一个漂亮的单标签音频播放器
本帖最后由 马黑黑 于 2024-6-10 16:58 编辑 <br /><br /><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; }
#player {
margin: auto;
margin-top: 100px;
margin-bottom: 50px;
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;
position: relative;
--color: #f58be8;
--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;
top: -30px;
text-align: justify;
text-align-last: justify;
font-size: 14px;
color: var(--color);
pointer-events: none;
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="player" data-time="00:00 00:00"></div>
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=28684483" autoplay loop></audio>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">style</span>></cl-cd>
<cl-cd data-idx="2">#player {</cl-cd>
<cl-cd data-idx="3"> <span class="tBlue">position:</span> absolute;</cl-cd>
<cl-cd data-idx="4"> <span class="tBlue">left:</span> 120px;</cl-cd>
<cl-cd data-idx="5"> <span class="tBlue">top:</span> 120px;</cl-cd>
<cl-cd data-idx="6"> <span class="tBlue">width:</span> 280px;</cl-cd>
<cl-cd data-idx="7"> <span class="tBlue">height:</span>10px;</cl-cd>
<cl-cd data-idx="8"> <span class="tBlue">background:</span> linear-gradient(to right, <span class="tBlue">var</span>(--color) <span class="tBlue">var</span>(--prg), transparent 0);</cl-cd>
<cl-cd data-idx="9"> <span class="tBlue">border:</span> 1px solid <span class="tBlue">var</span>(--color);</cl-cd>
<cl-cd data-idx="10"> <span class="tBlue">border-radius:</span> 6px;</cl-cd>
<cl-cd data-idx="11"> <span class="tBlue">display:</span> grid;</cl-cd>
<cl-cd data-idx="12"> <span class="tBlue">place-items:</span> center;</cl-cd>
<cl-cd data-idx="13"> <span class="tBlue">--color:</span> #f58be8;</cl-cd>
<cl-cd data-idx="14"> <span class="tBlue">--prg:</span> 0%;</cl-cd>
<cl-cd data-idx="15"> <span class="tBlue">--btnSize:</span> 50px;</cl-cd>
<cl-cd data-idx="16">}</cl-cd>
<cl-cd data-idx="17">#player::before, #player::after { <span class="tBlue">position:</span> absolute; <span class="tBlue">content:</span> <span class="tMagenta">''</span>; }</cl-cd>
<cl-cd data-idx="18">#player::before {</cl-cd>
<cl-cd data-idx="19"> <span class="tBlue">width:</span> <span class="tBlue">var</span>(--btnSize);</cl-cd>
<cl-cd data-idx="20"> <span class="tBlue">height:</span> <span class="tBlue">var</span>(--btnSize);</cl-cd>
<cl-cd data-idx="21"> <span class="tBlue">top:</span> calc(<span class="tBlue">var</span>(--btnSize) * -1 - 5px);</cl-cd>
<cl-cd data-idx="22"> <span class="tBlue">background:</span> url(<span class="tMagenta">'https://638183.freep.cn/638183/t23/btn/f5.png'</span>) no-repeat center/cover;</cl-cd>
<cl-cd data-idx="23"> <span class="tBlue">animation:</span> rot 6s linear infinite <span class="tBlue">var</span>(--state);</cl-cd>
<cl-cd data-idx="24">}</cl-cd>
<cl-cd data-idx="25">#player::after {</cl-cd>
<cl-cd data-idx="26"> <span class="tBlue">content:</span> attr(data-time);</cl-cd>
<cl-cd data-idx="27"> <span class="tBlue">inset:</span> -30px 0 10px 0;</cl-cd>
<cl-cd data-idx="28"> <span class="tBlue">text-align:</span> justify;</cl-cd>
<cl-cd data-idx="29"> <span class="tBlue">text-align-last:</span> justify;</cl-cd>
<cl-cd data-idx="30"> <span class="tBlue">font-size:</span> 14px;</cl-cd>
<cl-cd data-idx="31"> <span class="tBlue">color:</span> <span class="tBlue">var</span>(--color);</cl-cd>
<cl-cd data-idx="32">}</cl-cd>
<cl-cd data-idx="33">@keyframes rot { to { <span class="tBlue">transform:</span> rotate(360deg); } }</cl-cd>
<cl-cd data-idx="34"><<span class="tDarkRed">/style</span>></cl-cd>
<cl-cd data-idx="35"> </cl-cd>
<cl-cd data-idx="36"><<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"player"</span> data-time=<span class="tMagenta">"00:00 00:00"</span>><<span class="tDarkRed">/div</span>></cl-cd>
<cl-cd data-idx="37"><<span class="tDarkRed">audio</span> <span class="tRed">id</span>=<span class="tMagenta">"aud"</span> src=<span class="tMagenta">"https://music.163.com/song/media/outer/url?<span class="tRed">id</span>=28684483"</span> autoplay loop><<span class="tDarkRed">/audio</span>></cl-cd>
<cl-cd data-idx="38"> </cl-cd>
<cl-cd data-idx="39"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="40"><span class="tBlue">const</span> vids = <span class="tRed">document</span>.querySelectorAll(<span class="tMagenta">'.vid'</span>);</cl-cd>
<cl-cd data-idx="41"><span class="tBlue">const</span> btnSize = parseInt(<span class="tRed">window</span>.getComputedStyle(player).getPropertyValue(<span class="tMagenta">'--btnSize'</span>));</cl-cd>
<cl-cd data-idx="42"> </cl-cd>
<cl-cd data-idx="43"><span class="tBlue">const</span> mState = () => {</cl-cd>
<cl-cd data-idx="44"> player.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="45"> <span class="tBlue">if</span>(vids.length > 0) vids.forEach(vid => aud.paused ? vid.pause() : vid.play());</cl-cd>
<cl-cd data-idx="46">};</cl-cd>
<cl-cd data-idx="47"> </cl-cd>
<cl-cd data-idx="48"><span class="tBlue">const</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="49"> </cl-cd>
<cl-cd data-idx="50">aud.onplaying = aud.onpause = () => mState();</cl-cd>
<cl-cd data-idx="51"> </cl-cd>
<cl-cd data-idx="52">aud.ontimeupdate = () => {</cl-cd>
<cl-cd data-idx="53"> player.style.setProperty(<span class="tMagenta">'--prg'</span>, (aud.currentTime / aud.duration * 100 || 0) + <span class="tMagenta">'%'</span>);</cl-cd>
<cl-cd data-idx="54"> player.dataset.time = s2m(aud.currentTime) + <span class="tMagenta">' '</span> + s2m(aud.duration);</cl-cd>
<cl-cd data-idx="55">}</cl-cd>
<cl-cd data-idx="56"> </cl-cd>
<cl-cd data-idx="57">player.onclick = (e) => {</cl-cd>
<cl-cd data-idx="58"> <span class="tBlue">if</span>(e.offsetY > 0) aud.currentTime = aud.duration * e.offsetX / player.offsetWidth;</cl-cd>
<cl-cd data-idx="59"> <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="60">}</cl-cd>
<cl-cd data-idx="61"> </cl-cd>
<cl-cd data-idx="62">player.onmousemove = (e) => {</cl-cd>
<cl-cd data-idx="63"> <span class="tBlue">if</span>(e.offsetY < 0) {</cl-cd>
<cl-cd data-idx="64"> <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="65"> player.title = aud.paused ? <span class="tMagenta">'播放'</span> : <span class="tMagenta">'暂停'</span>;</cl-cd>
<cl-cd data-idx="66"> player.style.cursor = <span class="tMagenta">'pointer'</span>;</cl-cd>
<cl-cd data-idx="67"> }</cl-cd>
<cl-cd data-idx="68"> }<span class="tBlue">else</span>{</cl-cd>
<cl-cd data-idx="69"> player.title = <span class="tMagenta">'调节进度'</span>;</cl-cd>
<cl-cd data-idx="70"> player.style.cursor = <span class="tMagenta">'pointer'</span>;</cl-cd>
<cl-cd data-idx="71"> }</cl-cd>
<cl-cd data-idx="72">};</cl-cd>
<cl-cd data-idx="73"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<script>
const vids = document.querySelectorAll('.vid');
const btnSize = parseInt(window.getComputedStyle(player).getPropertyValue('--btnSize'));
const mState = () => {
player.style.setProperty('--state',['running','paused'][+aud.paused]);
if(vids.length > 0) vids.forEach(vid => aud.paused ? vid.pause() : vid.play());
};
const s2m = (s) => (Math.floor(s / 60)).toString().padStart(2, '0') + ':' + (Math.floor(s % 60)).toString().padStart(2, '0');
aud.onplaying = aud.onpause = () => mState();
aud.ontimeupdate = () => {
player.style.setProperty('--prg', (aud.currentTime / aud.duration * 100 || 0) + '%');
player.dataset.time = s2m(aud.currentTime) + ' ' + s2m(aud.duration);
}
player.onclick = (e) => {
if(e.offsetY > 0) aud.currentTime = aud.duration * e.offsetX / player.offsetWidth;
if(e.offsetY < 0 && e.offsetX > player.offsetWidth / 2 - btnSize / 2 && e.offsetX < player.offsetWidth / 2 + btnSize / 2) aud.paused ? aud.play() : aud.pause();
}
player.onmousemove = (e) => {
if(e.offsetY < 0) {
if(e.offsetX > player.offsetWidth / 2 - btnSize / 2 && e.offsetX < player.offsetWidth / 2 + btnSize / 2) {
player.title = aud.paused ? '播放' : '暂停';
player.style.cursor = 'pointer';
}
}else{
player.title = '调节进度';
player.style.cursor = 'pointer';
}
};
</script> 使用方法:
(一)播放器HTML代码放置在帖子内,改变CSS选择器 #player 的 left 和 top 属性定位播放器位置;
(二)audio 标签要求 id="aud";
(三)如果有视频且需要与音频同步管理,要求视频 class="vid";
(四)旋转按钮需要一张合适的背景图片。按钮尺寸的改变请通过修改 #player 选择器的 CSS变量 --btnSize 的赋值,px像素单位;
(五)假若帖子有其它需要通过 CSS变量 --state 进行控制,请修改JS代码 mState 函数的 player.style.setProperty('--prg',...) 中的 player 为帖子容器元素的 id,例如 tiezi 新产品出来了,黑黑厉害的~~~{:4_178:} 马老师端午节安康!太漂亮了,我收藏了! 亚伦影音工作室 发表于 2024-6-10 11:47
马老师端午节安康!太漂亮了,我收藏了!
节日好 醉美水芙蓉 发表于 2024-6-10 11:38
真漂亮!老师端午安康!
{:4_190:} 小辣椒 发表于 2024-6-10 11:46
新产品出来了,黑黑厉害的~~~
{:4_190:} 新创意层出不穷!看来是很有用的。 端午安康
https://p4.itc.cn/q_70/images03/20210612/796524c78b654712af09305cdfbf0091.gif 樵歌 发表于 2024-6-10 17:39
端午安康
蟹蟹 这个应该是复习呢,非常清晰的思路,很漂亮{:4_199:} 还考虑了视频和其他元素的加载,非常细致{:4_199:} 红影 发表于 2024-6-10 20:08
还考虑了视频和其他元素的加载,非常细致
顺带的 红影 发表于 2024-6-10 20:07
这个应该是复习呢,非常清晰的思路,很漂亮
有所不同的 马黑黑 发表于 2024-6-10 20:15
顺带的
这样的顺带很周到{:4_187:} 马黑黑 发表于 2024-6-10 20:16
有所不同的
嗯嗯,效果一样漂亮{:4_187:} 红影 发表于 2024-6-10 22:09
这样的顺带很周到
周到不周到不知道,只是手到{:4_170:} 红影 发表于 2024-6-10 22:10
嗯嗯,效果一样漂亮
我准备封装一下,不过歌词的动画或许有所不同 马黑黑 发表于 2024-6-10 22:28
周到不周到不知道,只是手到
心意也到了{:4_187:}