马黑黑 发表于 2022-6-11 23:07

歌词同步+进度可调audio播放器帖子模板(2022.6.11)

<style>
/*帖子外层盒子*/
.mama { position: relative; margin: auto; width: 1000px; height: 600px; background: transparent linear-gradient(to right bottom, darkgreen, snow); box-shadow: 2px 2px 2px #444; }
/*播放器外层盒子*/
.lrcWrap { position: absolute; top: 10px; left: 10px; padding: 20px; width: fit-content; height: fit-content; text-align: center; background: transparent linear-gradient(rgba(255,255,255,.25), rgba(255,255,255,.15)); box-shadow: 2px 2px 4px #eee; display: flex; flex-direction: column;align-items: center; }
/*播放控制外层盒子*/
.meterWrap { position: relative; display: flex; align-items: center; width: fit-content; height: 50px; }
/*播放按钮*/
.playbtn { width: 10px; height: 20px; background: #eee; clip-path: polygon(0 0, 0% 100%, 100% 50%); cursor: pointer; }
/*播放按钮鼠标滑过*/
.playbtn:hover { background: red; }
/*暂停按钮*/
.pausebtn { width: 2px; height: 20px; border-style: solid; border-width: 0px 4px; border-color: transparent #eee; display: none; cursor: pointer; }
/*暂停按钮鼠标滑过*/
.pausebtn:hover { border-color: transparent red; }
/*进度条*/
.meter { position: relative; width:300px; height: 11px; cursor: pointer; background: linear-gradient(transparent 5px, snow 6px,transparent 0); }
/*进度滑块*/
.slider { display: block; position: absolute; width: 4px; height: 100%; background: white; }
/*歌词面板外层盒子*/
.lrcWrap p { margin: 0 0 12px 0; padding: 0px; color: #ccc; font: normal 1.2em sans-serif; text-shadow: 1px 1px 1px #333; }
/*歌词区域限制层*/
.lrcBox { margin: 0; padding: 0; width: 400px; height: 72px; overflow: hidden; user-select: none; position: relative; }
/*歌词ul标签*/
.lrcUl { position: relative; top: 0; margin: 0; padding: 0; }
/*歌词li标签*/
.lrcUl li { margin: 0; padding: 0; height: 24px; font: normal 18px / 24px sans-serif; color: gray; text-shadow: 1px 1px 1px black; list-style-type: none; }
</style>

<div class="mama">
        <!-- 播放器开始 -->
        <div class="lrcWrap">
                <p>帖子标题</p>
                <div class="lrcBox"><ul class="lrcUl"></ul></div>
                <div class="meterWrap">
                        <div class="playbtn"></div>
                        <div class="pausebtn"></div>
                        <div class="meter"><span class="slider"></span></div>
                </div>
        <!-- 播放器结束 -->
        </div>
</div>
<audio class="aud" src="音频地址" autoplay="autoplay" loop="loop"></audio>

<script>
//N多盒子句柄
let aud = document.querySelector('.aud'),
        playbtn = document.querySelector('.playbtn'),
        pausebtn = document.querySelector('.pausebtn'),
        meter = document.querySelector('.meter'),
        slider = document.querySelector('.slider'),
        lrcUl = document.querySelector('.lrcUl');
let slip = 0; //误差修正
//lrc歌词数组
let lrcAr = [
        ['0.00','第一句'],
        ['3.84','第二句'],
        //...第N句
        ['331.05','最后一句']
];
//将歌词写入li标签
for(j=0; j<lrcAr.length; j++){
        lrcUl.innerHTML += '<li id="li' + lrcAr + '" style="list-style-type: none">' + lrcAr + '</li>';
}
//监听进度
aud.addEventListener('timeupdate', () => {
        let prog = (meter.clientWidth - slider.clientWidth) * aud.currentTime / aud.duration;
        slider.style.transform = 'translate(' + prog + 'px)';
        let tt = aud.currentTime;
        for(j=0; j<lrcAr.length; j++){
                if(tt >= lrcAr - slip){
                        if(j > 0){
                                let idxLast = lrcAr;
                                document.getElementById('li' + idxLast).style.color = 'gray';
                                lrcUl.style.top = '-' + (j * 24 - 24) + 'px';
                        }
                        let idx = lrcAr;
                        document.getElementById('li' + idx).style.color = 'ghostwhite';
                }
        }
})
//监听结束事件
aud.addEventListener('ended', () => {
        document.getElementById("li" + lrcAr).style.color = 'gray';
        lrcUl.style.top = 0;
})
//监听暂停与播放
aud.addEventListener('pause', () => btnstate(1));
aud.addEventListener('play',() => btnstate(0));
//进度条点击事件
meter.onclick = (e) => {
        e = e || event;
        aud.currentTime = (e.clientX - offset(meter,"left")) * aud.duration / meter.clientWidth;
}
//暂停与播放按钮点击事件
pausebtn.onclick = () => { aud.pause(); btnstate(1); }
playbtn.onclick = () => { aud.play(); btnstate(0); }
//获取进度条偏移总量
let offset = (obj,direction) => {
        let offsetDir = "offset" + direction.toUpperCase() + direction.substring(1);
        let realNum = obj;
        let positionParent = obj.offsetParent;
        while(positionParent != null){
                realNum += positionParent;
                positionParent = positionParent.offsetParent;
        }
        return realNum;
}
//按钮状态
let btnstate = (paused) => {
        paused == 1 ? (playbtn.style.display = 'block', pausebtn.style.display = 'none') : (playbtn.style.display = 'none', pausebtn.style.display = 'block');
}
//初始化按钮状态
aud.paused ? btnstate(1) : btnstate(0);

</script>

马黑黑 发表于 2022-6-11 23:10

<style>
.mama { position: relative; left: -202px; width: 1000px; height: 600px; background: transparent linear-gradient(to right bottom, darkgreen, snow); box-shadow: 2px 2px 2px #444; }
.lrcWrap { position: absolute; top: 10px; left: 10px; padding: 20px; width: fit-content; height: fit-content; text-align: center; background: transparent linear-gradient(rgba(255,255,255,.25), rgba(255,255,255,.15)); box-shadow: 2px 2px 4px #eee; display: flex; flex-direction: column;align-items: center; }
.meterWrap { position: relative; display: flex; align-items: center; width: fit-content; height: 50px; }
.playbtn { width: 10px; height: 20px; background: #eee; clip-path: polygon(0 0, 0% 100%, 100% 50%); cursor: pointer; }
.playbtn:hover { background: red; }
.pausebtn { width: 2px; height: 20px; border-style: solid; border-width: 0px 4px; border-color: transparent #eee; display: none; cursor: pointer; }
.pausebtn:hover { border-color: transparent red; }
.meter { position: relative; width:300px; height: 11px; cursor: pointer; background: linear-gradient(transparent 5px, snow 6px,transparent 0); }
.slider { display: block; position: absolute; width: 4px; height: 100%; background: white; }
.lrcWrap p { margin: 0 0 12px 0; padding: 0px; color: #ccc; font: normal 1.2em sans-serif; text-shadow: 1px 1px 1px #333; }
.lrcBox { margin: 0; padding: 0; width: 400px; height: 72px; overflow: hidden; user-select: none; position: relative; }
.lrcUl { position: relative; top: 0; margin: 0; padding: 0; }
.lrcUl li { margin: 0; padding: 0; height: 24px; font: normal 18px / 24px sans-serif; color: gray; text-shadow: 1px 1px 1px black; list-style-type: none; }
</style>

<div class="mama">
        <div class="lrcWrap">
                <p>帖子标题</p>
                <div class="lrcBox"><ul class="lrcUl"></ul></div>
                <div class="meterWrap">
                        <div class="playbtn"></div>
                        <div class="pausebtn"></div>
                        <div class="meter"><span class="slider"></span></div>
                </div>
        </div>
</div>
<audio class="aud" src="https://music.163.com/song/media/outer/url?id=1432843317.mp3" autoplay="autoplay" loop="loop"></audio>

<script>
let aud = document.querySelector('.aud'),
        playbtn = document.querySelector('.playbtn'),
        pausebtn = document.querySelector('.pausebtn'),
        meter = document.querySelector('.meter'),
        slider = document.querySelector('.slider'),
        lrcUl = document.querySelector('.lrcUl');
let slip = 0;
let lrcAr = [
        ['0.00','月牙泉 - 原唱 田震'],
        ['3.84','月牙泉童声版 - 翻唱 史筱璇'],
        ['6.79','词:杨海潮'],
        ['10.28','曲:杨海潮'],
        ['13.82','就在天的那边 很远很远'],
        ['18.01','有美丽的月牙泉'],
        ['22.84','它是天的镜子 沙漠的眼'],
        ['27.43','星星沐浴的乐园'],
        ['32.04','从那年我月牙泉边走过'],
        ['37.06','从此以后魂儿绕梦牵'],
        ['41.83','也许你们不懂得这种爱恋'],
        ['46.39','除非也去那里看看'],
        ['50.55','看那 看那 月牙泉'],
        ['59.72','想那 念那 月牙泉'],
        ['78.90','看那 看那 月牙泉'],
        ['88.19','想那 念那 月牙泉'],
        ['98.10','看那 看那 月牙泉'],
        ['107.10','想那 念那 月牙泉'],
        ['117.15','就在天的那边 很远很远'],
        ['121.70','有美丽的月牙泉'],
        ['126.40','它是天的镜子 沙漠的眼'],
        ['131.05','星星沐浴的乐园']
];

for(j=0; j<lrcAr.length; j++){
        lrcUl.innerHTML += '<li id="li' + lrcAr + '" style="list-style-type: none">' + lrcAr + '</li>';
}

aud.addEventListener('timeupdate', () => {
        let prog = (meter.clientWidth - slider.clientWidth) * aud.currentTime / aud.duration;
        slider.style.transform = 'translate(' + prog + 'px)';
        let tt = aud.currentTime;
        for(j=0; j<lrcAr.length; j++){
                if(tt >= lrcAr - slip){
                        if(j > 0){
                                let idxLast = lrcAr;
                                document.getElementById('li' + idxLast).style.color = 'gray';
                                lrcUl.style.top = '-' + (j * 24 - 24) + 'px';
                        }
                        let idx = lrcAr;
                        document.getElementById('li' + idx).style.color = 'ghostwhite';
                }
        }
})

aud.addEventListener('ended', () => {
        document.getElementById("li" + lrcAr).style.color = 'gray';
        lrcUl.style.top = 0;
})

aud.addEventListener('pause', () => btnstate(1));
aud.addEventListener('play',() => btnstate(0));

meter.onclick = (e) => {
        e = e || event;
        aud.currentTime = (e.clientX - offset(meter,"left")) * aud.duration / meter.clientWidth;
}

pausebtn.onclick = () => { aud.pause(); btnstate(1); }
playbtn.onclick = () => { aud.play(); btnstate(0); }

let offset = (obj,direction) => {
        let offsetDir = "offset" + direction.toUpperCase() + direction.substring(1);
        let realNum = obj;
        let positionParent = obj.offsetParent;
        while(positionParent != null){
                realNum += positionParent;
                positionParent = positionParent.offsetParent;
        }
        return realNum;
}

let btnstate = (paused) => {
        paused == 1 ? (playbtn.style.display = 'block', pausebtn.style.display = 'none') : (playbtn.style.display = 'none', pausebtn.style.display = 'block');
}

aud.paused ? btnstate(1) : btnstate(0);
</script>

马黑黑 发表于 2022-6-11 23:13

主要更新:

一、重新绘制了播放与暂停按钮;
二、修复、调整JS部分功能实现机制;
三、加入简单注释

红影 发表于 2022-6-12 08:06

加了这么多注释,这个更清楚了。黑黑真棒{:4_187:}

马黑黑 发表于 2022-6-12 08:10

红影 发表于 2022-6-12 08:06
加了这么多注释,这个更清楚了。黑黑真棒

还是简单的注释呢,细节的都没加

红影 发表于 2022-6-12 08:11

播放与暂停按钮是绘制的,比前面直接用符号漂亮多了{:4_199:}

马黑黑 发表于 2022-6-12 08:23

红影 发表于 2022-6-12 08:11
播放与暂停按钮是绘制的,比前面直接用符号漂亮多了

最主要是,他不会受到客户端字体的影响

加林森 发表于 2022-6-12 10:56

谢谢老黑。我来学习了。{:4_190:}

马黑黑 发表于 2022-6-12 11:34

加林森 发表于 2022-6-12 10:56
谢谢老黑。我来学习了。

{:5_108:}

红影 发表于 2022-6-12 11:35

马黑黑 发表于 2022-6-12 08:10
还是简单的注释呢,细节的都没加

已经非常清楚了,黑黑很细心{:4_187:}

红影 发表于 2022-6-12 11:36

马黑黑 发表于 2022-6-12 08:23
最主要是,他不会受到客户端字体的影响

对,这样不会受字体限制,这个之前倒没想到。

马黑黑 发表于 2022-6-12 11:36

红影 发表于 2022-6-12 11:35
已经非常清楚了,黑黑很细心

本来应该有些注释的习惯,个人觉得好简单的东东就不怎么写

马黑黑 发表于 2022-6-12 11:38

红影 发表于 2022-6-12 11:36
对,这样不会受字体限制,这个之前倒没想到。

不同的客户端字体不一样,还有,有些人会强制字体很大(这样按钮样式就会被破坏)

红影 发表于 2022-6-12 14:49

马黑黑 发表于 2022-6-12 11:36
本来应该有些注释的习惯,个人觉得好简单的东东就不怎么写

这样注释了更清晰,非常好。用最新的这个做了个帖子,本来想把那个频谱变小放旁边,发现不行呢,也许JS都要调用监听,冲突了吧,反正我弄不进去。实在不行弄个动图吧{:4_173:}

红影 发表于 2022-6-12 14:50

马黑黑 发表于 2022-6-12 11:38
不同的客户端字体不一样,还有,有些人会强制字体很大(这样按钮样式就会被破坏)

哦 哦,还是现在的好,可以回避这些问题了。{:4_187:}

马黑黑 发表于 2022-6-12 15:11

红影 发表于 2022-6-12 14:50
哦 哦,还是现在的好,可以回避这些问题了。

感觉好了一些吧

马黑黑 发表于 2022-6-12 15:14

红影 发表于 2022-6-12 14:49
这样注释了更清晰,非常好。用最新的这个做了个帖子,本来想把那个频谱变小放旁边,发现不行呢,也许JS都 ...

频谱本身就是一个播放器,不能简单叠加,但可以将频谱的内容加以处理,然后将实现它的相关代码加入到 timeupdate 监听事件里

加林森 发表于 2022-6-12 15:19

马黑黑 发表于 2022-6-12 11:34


{:5_108:}

小辣椒 发表于 2022-6-12 18:05

谢谢黑黑,这个是新的模板吧,收藏一下了,{:4_187:}

马黑黑 发表于 2022-6-12 18:08

小辣椒 发表于 2022-6-12 18:05
谢谢黑黑,这个是新的模板吧,收藏一下了,

这是最新更新的,也基本定型了吧
页: [1] 2 3
查看完整版本: 歌词同步+进度可调audio播放器帖子模板(2022.6.11)