马黑黑 发表于 2022-8-26 07:06

童安格 -耶利亚女郎

本帖最后由 马黑黑 于 2022-8-26 07:54 编辑 <br /><br /><style>
        #papa { left: -214px; width: 1024px; height: 640px; box-shadow: 3px 3px 20px #000; background: gray url('https://638183.freep.cn/638183/t22/hl/tong.webp') no-repeat center/cover; position: relative; z-index: 1; }
        #mypic { position: absolute; top: 125px; right: 100px; width: 260px; transform: rotate(30deg); cursor: pointer; transition: all 2s; }
        #mypic:hover { box-shadow: -10px -10px 40px 10px rgba(255,255,255,.45); transform: scale(1.5); }
        #player { margin: auto; display: block; position: absolute; }
</style>

<div id="papa">
        <canvas id="player"></canvas>
        <img id="mypic" src="https://638183.freep.cn/638183/t22/hl/yly.webp" alt="" />
</div>

<script>
let ctx = player.getContext('2d'),
        w = player.width = 350, h = player.height = 100,
        startX = 30, startY = 70, radius = 16,
        flag = false,
        color = { lrc: 'lightblue', time: 'lightblue', track: '#ccc', prg: 'red', circle: 'lightblue', btn: 'snow', btnhover: 'red' };
        aud = new Audio();
let lrcAr = [
        ['0.01','童安格耶利亚女郎'],
        ['34.10','很远的地方有个女郎名字叫做耶利亚'],
        ['42.33','有人在传说她的眼睛看了使人更年轻'],
        ['50.62','如果你得到她的拥抱你就永远不会老'],
        ['59.15','为了这个神奇的传说我要努力去寻找'],
        ['66.42','耶利亚神秘耶利亚耶利耶利亚'],
        ['74.77','耶利亚神秘耶利亚我一定要找到她'],
        ['101.12','很远的地方有个女郎名字叫做耶利亚'],
        ['109.32','有人在传说她的眼睛看了使人更年轻'],
        ['117.90','如果你得到她的拥抱你就永远不会老'],
        ['126.22','为了这个神奇的传说我要努力去寻找'],
        ['133.57','耶利亚神秘耶利亚耶利耶利亚'],
        ['141.90','耶利亚神秘耶利亚我一定要找到她'],
        ['150.29','耶利亚神秘耶利亚耶利耶利亚'],
        ['158.76','耶利亚神秘耶利亚我一定要找到她'],
        ['198.70','耶利亚神秘耶利亚耶利耶利亚'],
        ['207.11','耶利亚神秘耶利亚我一定要找到她'],
        ['215.28','耶利亚神秘耶利亚耶利耶利亚'],
        ['223.72','耶利亚神秘耶利亚我一定要找到她']
];

aud.src = 'https://music.163.com/song/media/outer/url?id=150852.mp3';
aud.autoplay = true;
aud.loop = true;

drawBtn(aud.paused);
drawProgress(2, '00:00');
drawLrc('等待播放 ...');

let isHover = (x, y, cx, cy) => Math.pow(x - cx, 2) + Math.pow(y - cy, 2) <= Math.pow(radius, 2); //鼠标经过检测

player.addEventListener('mousemove', (e) => { //监听鼠标经过
        flag = isHover(e.offsetX, e.offsetY, startX, startY);
        if(flag) {
                player.style.cursor = 'pointer';
                drawBtn(aud.paused);
        } else {
                player.style.cursor = 'default';
                drawBtn(aud.paused);
        }
});

player.addEventListener('click', (e) => { if(flag) aud.paused ? aud.play() : aud.pause(); });

aud.addEventListener('playing',()=> drawBtn(false));
aud.addEventListener('pause',()=> drawBtn(true));

aud.addEventListener('timeupdate', () => { //进度监听
        let prg = 100 * aud.currentTime / aud.duration;
        drawProgress(2*prg, toMin(aud.duration) + ' | ' + toMin(aud.currentTime));
        for(j = 0; j < lrcAr.length;j ++) {
                if(aud.currentTime >= lrcAr) drawLrc(lrcAr);
        }
});

function drawLrc(text) { //lrc同步
        ctx.clearRect(0, 0, w, 50);
        ctx.save();
        ctx.fillStyle = color.lrc;
        ctx.textAlign = 'center';
        ctx.beginPath();
        ctx.font = '1.2em sans-serif';
        ctx.fillText(text, w/2, 30);
        ctx.fill();
        ctx.restore();
}

function drawProgress(prog, text) { //进度
        ctx.clearRect(startX + radius + 202, startY - 10, startX + radius + 206 + ctx.measureText(text).width, 40);
        ctx.beginPath();
        ctx.font = '14px sans-serif';
        ctx.textBaseline = 'middle';
        ctx.strokeStyle = color.track;
        ctx.moveTo(startX + radius + 4, startY);
        ctx.lineTo(startX + radius + 204, startY); //底线
        ctx.stroke();
        ctx.beginPath();
        ctx.strokeStyle = color.prg;
        ctx.moveTo(startX + radius + 4, startY);
        ctx.lineTo(startX + radius + 4 + prog, startY); //进度线
        ctx.stroke();
        ctx.fillStyle = color.time;
        ctx.fillText(text, startX + radius + 208, startY); //数字进度
        ctx.fill();
}

function drawBtn(id) { //绘制播放+暂停按钮
        ctx.clearRect(startX - radius, startY - radius, radius *2, radius*2);
        ctx.fillStyle = color.circle;
        ctx.beginPath();
        ctx.arc(startX, startY, radius, 0, 2*Math.PI);
        ctx.fill();
        ctx.fillStyle = flag ? color.btnhover : color.btn;
        ctx.beginPath();
        if (id) { //播放图标
                ctx.lineWidth = 1;
                ctx.moveTo(startX-radius / 2 + 1, startY - radius / 2);
                ctx.lineTo(startX - radius / 2 + 1, startY + radius / 2);
                ctx.lineTo(startX + radius / 2 + 1, startY);
                ctx.fill();
        } else { //暂停图标
                ctx.fillRect(startX - radius / 2 + 5, startY - radius / 2, 2, radius);
                ctx.fillRect(startX - radius / 2 + 10, startY - radius / 2, 2, radius);
        }
}

function toMin(val) {
        if(!val) return '00:00';
        val = Math.floor(val);
        let min = parseInt(val / 60);
        let sec = parseFloat(val % 60);
        if(min < 10) min = '0' + min;
        if(sec < 10) sec = '0' + sec;
        return min + ':' + sec;
}
</script>

马黑黑 发表于 2022-8-26 07:09

本帖最后由 马黑黑 于 2022-8-26 07:54 编辑

本帖测试昨晚写的纯canvas画布播放器,代码尚未优化。完整源码分享如下:<style>
      #papa { left: -214px; width: 1024px; height: 640px; box-shadow: 3px 3px 20px #000; background: gray url('https://638183.freep.cn/638183/t22/hl/tong.webp') no-repeat center/cover; position: relative; z-index: 1; }
      #mypic { position: absolute; top: 125px; right: 100px; width: 260px; transform: rotate(30deg); cursor: pointer; transition: all 2s; }
      #mypic:hover { box-shadow: -10px -10px 40px 10px rgba(255,255,255,.45); transform: scale(1.5); }
      #player { margin: auto; display: block; position: absolute; }
</style>

<div id="papa">
      <canvas id="player"></canvas>
      <img id="mypic" src="https://638183.freep.cn/638183/t22/hl/yly.webp" alt="" />
</div>

<script>
let ctx = player.getContext('2d'),
      w = player.width = 350, h = player.height = 100,
      startX = 30, startY = 70, radius = 16,
      flag = false,
      color = { lrc: 'lightblue', time: 'lightblue', track: '#ccc', prg: 'red', circle: 'lightblue', btn: 'snow', btnhover: 'red' };
      aud = new Audio();
let lrcAr = [
      ['0.01','童安格耶利亚女郎'],
      ['34.10','很远的地方有个女郎名字叫做耶利亚'],
      ['42.33','有人在传说她的眼睛看了使人更年轻'],
      ['50.62','如果你得到她的拥抱你就永远不会老'],
      ['59.15','为了这个神奇的传说我要努力去寻找'],
      ['66.42','耶利亚神秘耶利亚耶利耶利亚'],
      ['74.77','耶利亚神秘耶利亚我一定要找到她'],
      ['101.12','很远的地方有个女郎名字叫做耶利亚'],
      ['109.32','有人在传说她的眼睛看了使人更年轻'],
      ['117.90','如果你得到她的拥抱你就永远不会老'],
      ['126.22','为了这个神奇的传说我要努力去寻找'],
      ['133.57','耶利亚神秘耶利亚耶利耶利亚'],
      ['141.90','耶利亚神秘耶利亚我一定要找到她'],
      ['150.29','耶利亚神秘耶利亚耶利耶利亚'],
      ['158.76','耶利亚神秘耶利亚我一定要找到她'],
      ['198.70','耶利亚神秘耶利亚耶利耶利亚'],
      ['207.11','耶利亚神秘耶利亚我一定要找到她'],
      ['215.28','耶利亚神秘耶利亚耶利耶利亚'],
      ['223.72','耶利亚神秘耶利亚我一定要找到她']
];

aud.src = 'https://music.163.com/song/media/outer/url?id=150852.mp3';
aud.autoplay = true;
aud.loop = true;

drawBtn(aud.paused);
drawProgress(2, '00:00');
drawLrc('等待播放 ...');

let isHover = (x, y, cx, cy) => Math.pow(x - cx, 2) + Math.pow(y - cy, 2) <= Math.pow(radius, 2); //鼠标经过检测

player.addEventListener('mousemove', (e) => { //监听鼠标经过
      flag = isHover(e.offsetX, e.offsetY, startX, startY);
      if(flag) {
                player.style.cursor = 'pointer';
                drawBtn(aud.paused);
      } else {
                player.style.cursor = 'default';
                drawBtn(aud.paused);
      }
});

player.addEventListener('click', (e) => { if(flag) aud.paused ? aud.play() : aud.pause(); });

aud.addEventListener('playing',()=> drawBtn(false));
aud.addEventListener('pause',()=> drawBtn(true));

aud.addEventListener('timeupdate', () => { //进度监听
      let prg = 100 * aud.currentTime / aud.duration;
      drawProgress(2*prg, toMin(aud.duration) + ' | ' + toMin(aud.currentTime));
      for(j = 0; j < lrcAr.length;j ++) {
                if(aud.currentTime >= lrcAr) drawLrc(lrcAr);
      }
});

function drawLrc(text) { //lrc同步
      ctx.clearRect(0, 0, w, 50);
      ctx.save();
      ctx.fillStyle = color.lrc;
      ctx.textAlign = 'center';
      ctx.beginPath();
      ctx.font = '1.2em sans-serif';
      ctx.fillText(text, w/2, 30);
      ctx.fill();
      ctx.restore();
}

function drawProgress(prog, text) { //进度
      ctx.clearRect(startX + radius + 202, startY - 10, startX + radius + 206 + ctx.measureText(text).width, 40);
      ctx.beginPath();
      ctx.font = '14px sans-serif';
      ctx.textBaseline = 'middle';
      ctx.strokeStyle = color.track;
      ctx.moveTo(startX + radius + 4, startY);
      ctx.lineTo(startX + radius + 204, startY); //底线
      ctx.stroke();
      ctx.beginPath();
      ctx.strokeStyle = color.prg;
      ctx.moveTo(startX + radius + 4, startY);
      ctx.lineTo(startX + radius + 4 + prog, startY); //进度线
      ctx.stroke();
      ctx.fillStyle = color.time;
      ctx.fillText(text, startX + radius + 208, startY); //数字进度
      ctx.fill();
}

function drawBtn(id) { //绘制播放+暂停按钮
      ctx.clearRect(startX - radius, startY - radius, radius *2, radius*2);
      ctx.fillStyle = color.circle;
      ctx.beginPath();
      ctx.arc(startX, startY, radius, 0, 2*Math.PI);
      ctx.fill();
      ctx.fillStyle = flag ? color.btnhover : color.btn;
      ctx.beginPath();
      if (id) { //播放图标
                ctx.lineWidth = 1;
                ctx.moveTo(startX-radius / 2 + 1, startY - radius / 2);
                ctx.lineTo(startX - radius / 2 + 1, startY + radius / 2);
                ctx.lineTo(startX + radius / 2 + 1, startY);
                ctx.fill();
      } else { //暂停图标
                ctx.fillRect(startX - radius / 2 + 5, startY - radius / 2, 2, radius);
                ctx.fillRect(startX - radius / 2 + 10, startY - radius / 2, 2, radius);
      }
}

function toMin(val) {
      if(!val) return '00:00';
      val = Math.floor(val);
      let min = parseInt(val / 60);
      let sec = parseFloat(val % 60);
      if(min < 10) min = '0' + min;
      if(sec < 10) sec = '0' + sec;
      return min + ':' + sec;
}
</script>



马黑黑 发表于 2022-8-26 07:17

JS代码全是基于canvas画布播放器。如果使用此播放器,color 实例化对象变量是修改播放器按钮文本等颜色的关键,应根据不同情境修改。现解释一下基于实例对象的 color 变量的键值对含义。原变量写成一行,为了方便解释,我们把它拆行:

color = {
        lrc: 'lightblue', //歌词颜色
        time: 'lightblue',//时间信息颜色
        track: '#ccc', //进度轨道颜色
        prg: 'red', //进度颜色
        circle: 'lightblue', //按钮圆圈颜色
        btn: 'snow', //播放暂停按钮颜色
        btnhover: 'red' //播放暂停按钮鼠标经过颜色
};

马黑黑 发表于 2022-8-26 07:25

写完后用了三种浏览器进行测试:最新版火狐、最新版edge(基于chromium)、最新版百分浏览器(基于较老版本的chromium),允许自动播放与否均能通过。但毕竟刚完成,代码一没有优化、精简,二没有仔细审核,不足与错误在所难免。

此外,用canvas画布做这个,代码量大一点是难以避免的,因为canvas的操作本身就是很琐碎的,每画一个东西都需要定义画笔相关属性,本来时女生才能干好的细活,俺一个大男人笨手笨脚,驱动画布的确是个磨炼。

马黑黑 发表于 2022-8-26 07:30

canvas画布是HTML的一个元素,在CSS中定义好position后,可以随意安排在帖子中任何位置。本帖将画布按默认方式摆放在左上角,其背景透明(默认),尺寸在JS中设置:

w = player.width = 350, h = player.height = 100,

加林森 发表于 2022-8-26 08:17

手机可以听见。

加林森 发表于 2022-8-26 08:55

电脑也没有问题。

醉美水芙蓉 发表于 2022-8-26 11:47

马黑黑 发表于 2022-8-26 12:41

醉美水芙蓉 发表于 2022-8-26 11:47
黑黑老师做贴辛苦了!论坛有你更精彩!

{:4_190:}

小辣椒 发表于 2022-8-26 15:08

原来黑黑已经分享教程了,黑神你太厉害了{:4_178:}

小辣椒 发表于 2022-8-26 15:10

马黑黑 发表于 2022-8-26 07:17
JS代码全是基于canvas画布播放器。如果使用此播放器,color 实例化对象变量是修改播放器按钮文本等颜色的关 ...

这个播放器是设置画布里面的,明白了,今天晚上不晓得可以不可以做出来,反正播放器我喜欢捣鼓的{:4_170:}

小辣椒 发表于 2022-8-26 15:11

马黑黑 发表于 2022-8-26 07:25
写完后用了三种浏览器进行测试:最新版火狐、最新版edge(基于chromium)、最新版百分浏览器(基于较老版本 ...

代码量大是黑黑辛苦,我们套用一样的

小辣椒 发表于 2022-8-26 15:13

马黑黑 发表于 2022-8-26 07:30
canvas画布是HTML的一个元素,在CSS中定义好position后,可以随意安排在帖子中任何位置。本帖将画布按默认 ...

明白了,谢谢黑黑,争取今天完成

红影 发表于 2022-8-26 16:11

画布还真是什么都能做,黑黑太厉害了{:4_199:}

红影 发表于 2022-8-26 16:23

全部是画出来,太不容易了。黑黑还加个mypic的鼠标操控,更不容易看懂了啊{:4_173:}

青青子衿 发表于 2022-8-26 17:10

小马黑黑老师,讲解的很清楚明了。。。。

青青子衿 发表于 2022-8-26 17:14

本帖最后由 青青子衿 于 2022-8-26 17:16 编辑

如果你得到她的拥抱,你就永远不会老。。。这是男们的梦想。。。。俺梦想,能骑着女巫的大扫把,提着阿拉丁神灯,夜里和星星月亮握个手

马黑黑 发表于 2022-8-26 19:17

青青子衿 发表于 2022-8-26 17:10
小马黑黑老师,讲解的很清楚明了。。。。

不过这个不是最终版本,还在改进中,在我的花园有一个比这好的版本

马黑黑 发表于 2022-8-26 19:18

小辣椒 发表于 2022-8-26 15:08
原来黑黑已经分享教程了,黑神你太厉害了

进度可控的版本等我折磨一下,争取今晚发出来

马黑黑 发表于 2022-8-26 19:18

青青子衿 发表于 2022-8-26 17:14
如果你得到她的拥抱,你就永远不会老。。。这是男们的梦想。。。。俺梦想,能骑着女巫的大扫把,提着阿拉丁 ...

要做巫婆呀{:4_170:}
页: [1] 2 3
查看完整版本: 童安格 -耶利亚女郎