<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100svh;
}
.music {
width: 300px;
height: 40vh;
overflow-y: hidden;
display: grid;
grid-template-columns: 1fr;
position: relative;
}
.music::-webkit-scrollbar {
display: none;
}
.music__wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
font-size: 16px;
line-height: 30px;
position: absolute;
top: 50%;
width: 100%;
height: 100%;
transition: all 1s linear;
}
.music__wrapper span {
background: linear-gradient(90deg, red 50%, #000 50%);
background-size: 200% auto;
background-position-x: -100%;
background-clip: text;
color: transparent;
}
.music__wrapper span.active {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
<div>
<input type="text" oninput="getChange(this)">
<button onclick="loadMusic()">加载</button>
</div>
<audio id="audio" controls></audio>
<div class="music">
<div class="music__wrapper">
</div>
</div>
<script>
function getChange(e) {
music.musicId = e.value;
}
function loadMusic() {
music.getMusic()
music.getLyrics()
}
class Music {
constructor(dom, audio) {
this.musicDOM = document.querySelector(dom)
this.audio = document.querySelector(audio)
this.musicId = 1297802566;
this.LyricesArr = [];
this.status = "pause"
this.audio.addEventListener("play", this.play.bind(this));
this.audio.addEventListener("timeupdate", this.timeupdate.bind(this))
this.audio.addEventListener("pause", this.pause.bind(this))
}
// 监听audio开始事件
play(e) {
this.status = "play"
this.animate?.play()
}
// 监听audio暂停事件
pause(e) {
this.status = "pause"
this.animate?.pause()
}
// 监听audio进度事件
timeupdate(e) {
const currentTime = e.target.currentTime;
let oldItem = null;
let item = null;
for(let i=this.LyricesArr.length-1;i>=0;i--){
const v = this.LyricesArr[i];
if (currentTime >= v.startTime) {
item = v;
break;
}else {
oldItem = v;
}
}
if (item === this.currentItem) return;
this.animate?.cancel();
if (item) {
console.log(currentTime,item.startTime);
this.startAnimate(item, oldItem, currentTime)
}
}
// 切割时间
getStartTime(time) {
let second = 0;
const times = time.split(":")
// 分钟
second += Number.parseFloat(times[0] * 60)
// 秒
second += Number.parseFloat(times[1]);
// 毫秒
return second.toFixed(2);
}
// 未完成 (废弃)
sendSearch(keyword) {
fetch(`http://10.7.44.129:8889/music/search?csrf_token=hlpretag=&hlposttag=&s=${keyword}&type=1&offset=0&total=true&limit=10`, {
method: "get",
credentials: 'include',
headers: {
},
}).then(res => res.json()).then(res => {
for (let i = 0; i < res.result.songs.length; i++) {
this.musicDOM.innerHTML += `<span>${res.result.songs[i]}</span>`
}
})
}
// 重新设置audio音乐地址
getMusic() {
// fetch(`http://localhost:8889/music/m/${this.musicId}`, {
// method: "get"
// }).then(res => res.blob()).then(res => {
// console.log(res);
// })
this.audio.src = `https://music.163.com/song/media/outer/url?id=${this.musicId}.mp3`
}
// 获取歌词
getLyrics() {
this.LyricesArr = [];
this.musicDOM.innerHTML = "";
//34367845
fetch(`http://10.7.44.129:8889/music/${this.musicId}`, {
method: "get"
}).then(res => res.json()).then(res => {
const Lyrics = res.lyric.split("\n").filter(item => item.length > 0);
for (let i = 0; i < Lyrics.length; i++) {
const lines = Lyrics[i].split("]");
if (lines[1].length <= 0) {
console.log(lines[0]);
continue};
const span = document.createElement("span");
span.innerHTML = `${lines[1]}`
this.musicDOM.appendChild(span);
this.LyricesArr.push({
startTime: this.getStartTime(lines[0].substring(1)),
dom: span,
index: this.LyricesArr.length
});
}
})
}
// 歌词滚动动画
startAnimate(item, oldItem, currentTime) {
this.musicDOM.style.top = `calc(50% - ${30 * item.index}px)`;
this.currentItem = item;
console.log(item.dom);
this.animate = item.dom.animate([
{ backgroundPositionX: "-100%" },
{ backgroundPositionX: "-200%" },
], {
iterations: 1,
duration: (oldItem.startTime -( item?.startTime??0)) * 1000,
easing: "linear",
})
this.animate.currentTime = (currentTime -item?.startTime??0) * 1000
if (this.status === "pause") {
this.animate?.pause();
}
function animationend() {
item.dom.removeEventListener("animationend", animationend)
}
item.dom.addEventListener("animationend", animationend)
}
}
const music = new Music(".music__wrapper", "#audio");
music.getMusic()
music.getLyrics()
</script>
</body>
</html>
拿到网易云的路由地址