使用HTML+CSS+JS做一个音乐播放器

一、观前说明:
1.本人为新手,很多地方可能写得不好,欢迎指正。

2.本人仍在学习CSS中,在本篇中若有写得不好的地方,欢迎指正。

3.本人尚未系统性的学习过JS(还没学到),在这里用到的JS全是靠以前学其他语言积累下的基础,因此在很多地方也会写得不够好,欢迎指正。

4.因HTML部分和CSS部分较为简单,本篇文章会更注重于讲JS部分,其中一些说明我会写在代码里面,我认为这比我写在外面更好理解。

5.我是将整个播放器写完了才写的这篇文章,所以你们在看代码的时候,会看到一些提前写了的代码,比如播放暂停还没讲到修改时间间距,但在代码处已经有了。

二、最终效果

2.1、包含功能

1.播放暂停

2.歌词动画,显示当前歌词

3.拖拽歌词,调整歌词进度

4.进度条调整歌词进度

5.音量控制

2.2、图片展示
使用HTML+CSS+JS做一个音乐播放器

三、现在开始

1.搭建基础框架

框架图:
使用HTML+CSS+JS做一个音乐播放器

按照框架图,搭建框架:

其中歌词是后面由JS创建的,因此只需要有一个div包住就行

<!DOCTYPE html>

<html lang="zh-CN">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<link rel="stylesheet" href="css/music.css" />
		<link rel="icon" href="img/icon.jpg" />
		<title>音乐播放器</title>
	</head>
	<body>
		<!-- 音乐 -->
		<audio src="audio/韩安旭 - 不在.mp3" preload=""></audio>
		<!-- 背景板 -->
		<div class="background">
			<!-- 音乐区 -->
			<div class="music-background">
				<!-- 左侧图片 -->
				<div class="img-back">
					<img src="img/musicCover2.jpg" alt="韩安旭 - 不在" />
				</div>
				<!-- 右侧歌词 -->
				<div class="lyrics-back">
					<!-- 歌曲信息 -->
					<div class="div-title">
						<h1></h1>
						<p style="margin-right: 100px">
							专辑:
							<span></span>
						</p>
						<p>
							歌手:
							<span></span>
						</p>
					</div>
					<!-- 歌词信息 -->
					<div class="lyrics-time">
						<a href="#" class="goto"></a>
						<a href="#" class="goto-time">00:00</a>
					</div>
					<div class="div-lyrics"></div>
				</div>
			</div>
			<!-- 控制区 -->
			<div class="control-back">
				<!-- 进度条 -->
				<div class="progress-bar">
					<div class="progress-all"></div>
					<div class="progress-now"></div>
				</div>
				<span class="time">00:00/00:00</span>
				<!-- 控制按钮 -->
				<div class="control">
					<!-- 上一首、下一首、暂停播放 -->
					<div class="control-btn">
						<a href="#" class="up"></a>
						<a href="#" class="play-pause" onclick="setPlay()"></a>
						<a href="#" class="down"></a>
					</div>
					<!-- 播放模式、声音 -->
					<div class="control-right">
						<a href="#" class="mode"></a>
						<a href="#" class="volume" onclick="setMuted()"></a>
						<div class="volume-back">
							<div class="volume-all"></div>
							<div class="volume-now"></div>
						</div>
						<span class="volume-text">100</span>
					</div>
				</div>
			</div>
		</div>
		<script src="js/music.js"></script>
	</body>
</html>

2.CSS美化

2.1清除所有边距已经禁止选择

* {
    margin: 0;
    padding: 0;
    user-select: none;
}
 
h1 {
    font-weight: 500;
}

a {
    color: #000;
    text-decoration: none;
}

2.2设置背景样式(大盒子)

/* 背景样式,相当于body */
.background {
    width: 100vw;
    height: 100vh;
    background-color: #fff;
}
 
/* 上半部分样式,即包含封面以及歌词的盒子 */
.music-background {
    width: 1000px;
    height: calc(100vh - 200px);
    margin: 0 auto;
    overflow: hidden;
}
 
/* 图片盒子 */
.img-back {
    width: 300px;
    padding: 0 50px;
    margin-top: 150px;
    margin-right: 50px;
    overflow: hidden;
    float: left;
}
 
/* 歌词盒子 */
.lyrics-back {
    width: 550px;
    height: 100%;
    overflow: hidden;
    float: left;
}
 
/* 歌曲信息盒子 */
.div-title {
    width: 100%;
    height: 100px;
    margin-top: 150px;
}
 
/* 控制区域盒子 */
.control-back {
    width: 100vw;
    height: 80px;
    bottom: 0;
    position: absolute;
    background-color: rgba(255, 255, 255, 0.8);
}

2.3设置图片、字体样式

只是简简单单的调整大小边距等,甚至在歌曲信息中的文字段落标签我都没有设置字体大小,事实上这并不是一种好的习惯

.img-back img {
    width: 300px;
    height: 300px;
    border-radius: 20px;
}
 
.div-title h1 {
    width: 100%;
    height: 50px;
}

.div-title p {
    height: 50px;
    display: inline-block;
    color: rgba(0, 0, 0, 0.5);
}

.div-title span {
    color: #000;
}
 
.div-lyrics p {
    font-size: 15px;
    line-height: 34px;
}

2.4设置控制按钮、进度条、音量控制样式

这里我的控制按钮用的都是a标签,因此需要将a标签修改为行内块标签inline-block

其中".lyrics-time"是拖拽歌词时显示的调整进度的按钮,因此在默认状态下需要隐藏

.lyrics-time a {
    display: inline-block;
    position: absolute;
    display: none;
}

.goto {
    width: 20px;
    height: 20px;
    margin: 7px 15px;
    background: url(../img/play.png) no-repeat;
    background-position: 50% 50%;
    background-size: 20px;
}

.goto-time {
    width: 50px;
    height: 34px;
    margin-left: 550px;
    font-size: 13px;
    line-height: 34px;
    text-align: center;
    position: absolute;
    color: #5192fe;
}
 
/* 进度条 */
.progress-bar {
    width: calc(100vw - 100px);
    margin: 5px 0;
    padding: 5px 0;
    cursor: pointer;
    float: left;
}

/* 当前播放进度 */
.progress-now {
    width: 0;
    height: 1px;
    margin-top: -1px;
    background-color: #5192fe;
}

/* 总播放进度 */
.progress-all {
    width: 100%;
    height: 1px;
    background-color: #dee2e6;
}

/* 播放进度 文本 */
.time {
    display: inline-block;
    width: 90px;
    height: 21px;
    margin-left: 5px;
    text-align: center;
    color: rgba(128, 130, 133, 0.8);
    cursor: default;
    overflow: hidden;
}

/* 控制按钮 */
.control {
    width: 100%;
    height: 30px;
    margin-top: 19px;
}

.control a {
    margin: 0 5px;
    display: inline-block;
}

.control a:hover {
    opacity: 50%;
}

.control-btn {
    width: 130px;
    height: 30px;
    margin: 0 auto;
}

/* 上一首 */
.up {
    width: 30px;
    height: 30px;
    background: url(../img/up.png) no-repeat;
    background-size: 20px;
    background-position: 50% 50%;
}

/* 暂停播放 */
.play-pause {
    width: 30px;
    height: 30px;
    background: url(../img/play.png) no-repeat;
    background-size: 30px;
    background-position: 50% 50%;
}

/* 下一首 */
.down {
    width: 30px;
    height: 30px;
    background: url(../img/down.png) no-repeat;
    background-size: 20px;
    background-position: 50% 50%;
}

/* 右侧控制按钮 */
.control-right {
    /* width: 180px; */
    height: 30px;
    margin-left: calc(50vw + 150px);
    margin-top: -30px;
    display: flex;
    align-items: center;
}

/* 播放模式 */
.mode {
    width: 30px;
    height: 30px;
    background: url(../img/sequence.png) no-repeat;
    background-size: 20px;
    background-position: left 50%;
    cursor: pointer;
}

/* 声音控制 */
.volume {
    width: 30px;
    height: 30px;
    background: url(../img/volume.png) no-repeat;
    background-size: 20px;
    background-position: left 50%;
    cursor: pointer;
}

.volume-back {
    padding: 5px 0;
    cursor: pointer;
}

.volume-all {
    width: 100px;
    height: 2px;
    background-color: #e5e5e5;
}

.volume-now {
    width: 100px;
    height: 2px;
    margin-top: -2px;
    max-width: 100px;
    background-color: #5192fe;
}

.volume-text {
    margin-left: 10px;
    font-size: 14px;
}

3.JS部分

3.1首先是声明一些变量、数组等,因为这一部分是要多处使用的,因此在最开头就声明了

var myAduio = document.getElementsByTagName(‘audio‘)[0];
var divLyrics = document.getElementsByClassName(‘div-lyrics‘)[0];
var divTitle = document.getElementsByClassName(‘div-title‘)[0];
var lyricsTime = document.getElementsByClassName(‘lyrics-time‘)[0];
var lyricsTime_a = lyricsTime.getElementsByTagName(‘a‘);
var progressTime = document.getElementsByClassName(‘time‘)[0];
var nowLine = 0;
var lyricsMove = false;
var playState = false;
var lyrics, lyricsStyle, lyricsFirst, rollT;
var timeArray1 = new Array();
var timeArray2 = new Array();
var timeInterval = new Array();

这里面分别是

audio控件,播放音乐用的;

歌词div,到时候要在这里面创建歌词

歌曲信息div,也是在这里面修改歌曲信息的内容

拖拽歌词调整进度的div "lyricsTime"以及里面的按钮 "lyricsTime_a"

进度条右侧的时间"progressTime"

当前播放行"nowLine"

拖拽状态"lyricsMove"

播放状态"playState"

所有歌词的p标签"lyrics",第一行歌词的样式"lyricsStyle",第一行歌词的p标签"lyricsFirst",歌词滚动的计时器"rollT"

以秒数记录每一行歌词所在时间的数组"timeArray1"以及以分钟:秒数的星石记录每一行歌词所在时间的数组"timeArray2",用两种方式记录时间的原因是后面需要以这两种形式交叉使用,也可以只记录一种,在使用到另一种的时候将其算出来,但我感觉直接记录两种会更方便

记录每一行歌词时间间距的数组"timeInterval"

3.2页面加载完毕后就需要执行的方法

window.onload = function () {
	initialLyrics();
	lyricsStyle = getComputedStyle(lyricsFirst, null);
	setLyrics(0);
	setMouseEvent();
	setTimeText();
};

3.3初始化歌词(创建歌词并存储一些信息)

sp、ar、ti分别为专辑、艺术家、歌名

function initialLyrics() {
    let sp = divTitle.getElementsByTagName(‘span‘)[0];
    let ar = divTitle.getElementsByTagName(‘span‘)[1];
    let ti = divTitle.getElementsByTagName(‘h1‘)[0];
    let lyricsData, timeString;
    let lyricsArray = new Array();
    // 清除数组,先清除数组可以保证每一次存储的信息无误
    timeArray1.splice(0, timeArray1.length);
    timeArray2.splice(0, timeArray2.length);
    lyricsArray.splice(0, lyricsArray.length);
    // 按相同格式放入歌词更换歌曲即可达到相同效果
    lyricsData =
        ‘[ar]韩安旭\n[ti]不在\n[sp]不在\n[00:00.74]韩安旭 - 不在\n[00:01.76]词:尤雅琪\n[00:02.76]曲:胜屿\n[00:15.62]我累了就紧紧锁住情绪\n[00:18.11]不再放任它堆积\n[00:22.14]我痛了就静静屏住呼吸\n[00:26.02]不给想念留余地\n[00:28.88]只是下雨时会委屈\n[00:32.80]只是想起你会哭泣\n[00:36.77]没关系 真没关系\n[00:44.28]我终于学会一个人弹琴\n[00:47.12]只是弹琴没有你\n[00:49.29]我终于学会一个人做梦\n[00:54.85]只是做梦没有你\n[00:57.73]我依旧像从前粗心\n[01:01.09]时常会忘记星期几\n[01:05.00]却始终忘不掉你看我的眼睛\n[01:11.71]穿过了熙攘的人海\n[01:15.11]想找谁能把你取代\n[01:19.62]复制你曾给过我的\n[01:21.44]那种宠爱\n[01:26.32]掏空了回忆的脑海\n[01:30.75]寂寞却狠狠扑过来\n[01:33.69]措手不及 无法躲开\n[01:41.52]我承认是我太依赖\n[01:44.92]像个不懂事的小孩\n[01:48.35]挥霍掉我们的未来\n[01:51.22]才醒过来\n[01:55.15]我承认后悔了伤害\n[01:59.06]抛开你的好我的坏\n[02:02.14]直到如今学会忍耐 你不在\n[02:26.95]我终于学会一个人弹琴\n[02:29.33]只是弹琴没有你\n[02:33.26]我终于学会一个人做梦\n[02:36.64]只是做梦没有你\n[02:39.53]我依旧像从前粗心\n[02:42.90]时常会忘记星期几\n[02:46.82]却始终忘不掉你看我的眼睛\n[02:53.62]穿过了熙攘的人海\n[02:57.09]想找谁能把你取代\n[03:00.98]复制你曾给过我的\n[03:05.43]那种宠爱\n[03:08.25]掏空了回忆的脑海\n[03:11.67]寂寞却狠狠扑过来\n[03:15.56]措手不及 无法躲开\n[03:22.49]我承认是我太依赖\n[03:26.37]像个不懂事的小孩\n[03:30.38]挥霍掉我们的未来\n[03:33.80]才醒过来\n[03:37.81]我承认后悔了伤害\n[03:41.29]抛开你的好我的坏\n[03:44.73]直到如今学会忍耐 你不在‘;
    // 文本.split(‘分隔符‘),用于分割文本
    lyricsArray = lyricsData.split(‘\n‘);
    // 添加歌曲信息
    ar.innerText = lyricsArray[0].split(‘]‘)[1];
    ti.innerText = lyricsArray[1].split(‘]‘)[1];
    sp.innerText = lyricsArray[2].split(‘]‘)[1];
    // 添加歌词
    for (var i = 3; i < lyricsArray.length; i++) {
//这里i=3即我们的第一行歌词,将高度设置为100%,在页面创建完毕时添加一个上滚的动画
        if (i == 3) {
            divLyrics.innerHTML +=
                ‘<p style="margin-top: 100%;color:#5192fe;">‘ +
                lyricsArray[i].split(‘]‘)[1] +
                ‘</p>‘;
        } else {
            divLyrics.innerHTML +=
                ‘<p>‘ + lyricsArray[i].split(‘]‘)[1] + ‘</p>‘;
        }
    }

    // 获取后续需要使用的变量
    lyricsFirst = divLyrics.getElementsByTagName(‘p‘)[0];
    lyrics = divLyrics.getElementsByTagName(‘p‘);

    // 计算每局歌词所在的秒数
    timeArray1.push(0);
    for (var i = 0; i < lyrics.length; i++) {
        timeString = lyricsArray[i + 3].substring(1, 9).split(‘:‘);
        timeArray1.push(
            parseFloat(timeString[0]) * 60 + parseFloat(timeString[1])
        );
    }

    // 计算时间间隔,将时间从秒数改为分钟+秒数
    for (var i = 0; i < timeArray1.length - 1; i++) {
        timeInterval[i] = timeArray1[i + 1] - timeArray1[i];
        // timeArray2数组主要是显示使用的,在秒数部分,若为个位数,十位数补零会更为美观
        if (Math.floor(timeArray1[i] % 60) < 10) {
            timeArray2.push(
                Math.floor(timeArray1[i] / 60) +
                    ‘:0‘ +
                    Math.floor(timeArray1[i] % 60)
            );
        } else {
            timeArray2.push(
                Math.floor(timeArray1[i] / 60) +
                    ‘:‘ +
                    Math.floor(timeArray1[i] % 60)
            );
        }
    }
}

歌词初始化完后,整个页面就可以正常显示了,接下来先写控制播放暂停的功能

3.3播放暂停

// 设置播放状态
function setPlay(state) {
	var play_pause = document.getElementsByClassName(‘play-pause‘)[0];
	if (state == null) {
		// 如果歌曲为暂停状态,那么获取到的state则为true,将state设置为true我们就播放
		state = myAduio.paused;
	}
	// 清除计时器,不然会出现多个计时器同时进行
	clearTimeout(rollT);
	if (state == true) {
		myAduio.play();
		play_pause.style.backgroundImage = ‘url(../img/pause.png)‘;
		playState = true;
		// 开始播放的同时,同时开始设置时间进度文本,歌词滚动以及进度条位置
		setTimeText();
		lyricsRoll();
		setProgress();
	} else {
		myAduio.pause();
		play_pause.style.backgroundImage = ‘url(../img/play.png)‘;
		playState = false;
		// 暂停后重新修改计时器时间,这里后面会详细讲
		timeInterval[nowLine] = timeArray1[nowLine + 1] - myAduio.currentTime;
	}
}

3.4设置时间进度文本

// 设置进度文本
function setTimeText() {
	var nowTime = myAduio.currentTime;
	var allTime = myAduio.duration;
	// 计算时间,若为个位数,补0
	if (Math.floor(nowTime % 60) < 10) {
		nowTime = Math.floor(nowTime / 60) + ‘:0‘ + Math.floor(nowTime % 60);
	} else {
		nowTime = Math.floor(nowTime / 60) + ‘:‘ + Math.floor(nowTime % 60);
	}
	if (Math.floor(allTime % 60) < 10) {
		allTime = Math.floor(allTime / 60) + ‘:0‘ + Math.floor(allTime % 60);
	} else {
		allTime = Math.floor(allTime / 60) + ‘:‘ + Math.floor(allTime % 60);
	}
	progressTime.innerText = nowTime + ‘/‘ + allTime;
	// 每0.1秒执行一次
	if (myAduio.paused == false) {
		setTimeout(setTimeText, 100);
	}
}

3.5设置进度条位置

// 设置进度条进度
function setProgress() {
	let progress_now = document.getElementsByClassName(‘progress-now‘)[0];
	let progress_bar = document.getElementsByClassName(‘progress-bar‘)[0];
	let progress = Math.floor(
		(myAduio.currentTime / myAduio.duration) * progress_bar.clientWidth
	);
	progress_now.style.width = progress + ‘px‘;
	if (myAduio.paused == false) {
		setTimeout(setProgress, 100);
	}
}

到这里,除了歌词滚动、调整进度等,一个最简单的音乐播放器就已经完成了

3.6设置歌词位置

// 设置歌词位置
function setLyrics(line) {
	// 将当前歌词高亮,其余歌词都改为黑色
	for (let i = 0; i < lyrics.length; i++) {
		lyrics[i].style.color = ‘#000‘;
	}
	lyrics[line].style.color = ‘#5192fe‘;
	// 设置动画,这里只需要改变第一行歌词的位置即可
	// 这里是将第一行歌词的marginTop从当前的位置修改为当前进度歌词所在行的对应位置,因为我将p标签的行高设置为了34px,而我要将当前歌词在第五行显示,即前面要有四行空的,可以得到34*4=136px的marginTop,line * (-34) + 136即我需要向上移动多少行
	// 假设我的当前歌词是在第一行显示,当前歌词在第一行(数组从零开始,所以这里在数组里是0),那么marginTop就是0,即0 * (-34),当前歌词在第二行,那么marginTop就是-34px,即1 * (-34),往后以此类推
	// 同上,比如当前歌词在第一行,但是我需要将第一行歌词显示在第五行,即前面有四个空的位置,那么我第一行歌词就需要将marginTop修改到第五行的位置,那么第一行歌词的marginTop就是136px,即0 * (-34) +136
	let lyrics_animation = lyrics[0].animate(
		[
			{
				marginTop: lyricsStyle.marginTop,
			},
			{
				marginTop: line * -34 + 136 + ‘px‘,
			},
		],
		{
			duration: 100,
		}
	);
	//设置监视器,在动画完成之后,修改第一行歌词的marginTop,这里不用"fill:forwards"的原因是使用后,拖拽歌词将无法使用
	lyrics_animation.addEventListener(
		‘finish‘,
		function () {
			lyrics[0].style.marginTop = line * -34 + 136 + ‘px‘;
		},
		false
	);
}

设置歌词写好了,我们现在就需要考虑如何让歌词滚动起来,即让歌词自动到达当前行的位置

我想到的方法有两种

第一种方法是根据每句歌词之间的时间间隔,每过一个间隔,就触发一次方法,我这里用的就是这种方法;

第二种方法是每过很短的一段时间,就触发一次方法,就跟进度条类似;

我观察过酷狗以及QQ音乐,其中酷狗用的应该就是第一种方法,是过一个间隔触发一次的,而QQ音乐则是用的第二种方法。

我个人认为第二种方法写起来更简单,但是需要的性能更高,但是进度条、以及时间进度文本是必须使用第二种方法的(至少我想不到其他的),那么如果将进度条、时间进度文本、歌词滚动这三个方法放在一个计时器中调用,而不是像我这样分开三个计时器,哪一种是更优的方法就不得而知了,欢迎各位大佬给出自己的看法。

那么我们这里用第一种方法,首先我们先分析一下需要记录的内容(其实前面已经记录了,只是在这里才说)

第一个是要记录歌词,这个不需要多的解释,显示用的

第二个需要记录时间间隔,这个是用来设置计时器的

第三个需要记录每一行歌词所在的时间,分两个记录,一个按秒数记录,用来拖拽歌词时调整进度;另一个按分:秒记录,用于拖拽歌词时显示时间;两个数组可只记录一个,用到另一个的时候算出来就好,我为了方便就记录了两个

前面三个都是要用数组记录,第四个则是非数组,用于记录当前歌词到了哪一行,在歌词滚动中,歌词回弹等地方都会用到。

需要记录的东西我们分析完了,那么接下来在画一个逻辑图来分析计时器要如何设置,即歌词滚动要如何实现

使用HTML+CSS+JS做一个音乐播放器

分析完毕,那么继续

3.7歌词滚动

// 歌词滚动
// 歌词滚动的方法只需要按照时间间隔设置计时器即可
function lyricsRoll() {
	rollT = setTimeout(function () {
		if (nowLine < lyrics.length && myAduio.paused == false) {
			if (lyricsMove == false) {
				setLyrics(nowLine);
			}
			nowLine += 1;
			lyricsRoll();
		}
	}, timeInterval[nowLine] * 1000);
}

// 以下代码不在这个地方,在设置播放状态处,只是放在这里做解释
// 每当我们暂停歌曲时,我们就需要将当前行到下一行即从i到i+1的时间间距,从原来的,修改为剩余的,比如本来跳到下一行需要10s,而我是在第5s的时候暂停的,那么剩余时间就是5s,但我们无法直接知道在这一行歌词我们用了多少时间,所以我们就要用下一行歌词的时间(不是间距,而是在整首歌中这一行歌词在哪一秒)减去当前的播放进度,这样得到的值就是我们需要的剩余间距,所以代码是
timeInterval[nowLine] = timeArray1[nowLine + 1] - myAduio.currentTime;

到这里,播放器的歌词滚动部分已经写好了,但现在的播放器只能播放暂停,看到歌词在哪,不能调整进度等,接下来我们就来解决这个问题

3.8歌词拖拽、音量控制、调整进度

function setMouseEvent() {
	// 歌词拖拽
	let lyrics_Y, line;
	// 此处是调整歌词位置,以及计算用户将歌词拖拽到了哪一行
	divLyrics.onmousedown = function (e) {
		if (lyricsMove == false) {
			lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
				‘block‘;
			lyricsMove = true;
		}
		lyrics_Y = parseInt(lyricsStyle.marginTop);
		document.onmousemove = function (event) {
			lyricsFirst.style.marginTop =
				event.clientY - (e.clientY - lyrics_Y) + ‘px‘;
			line = Math.floor(-(parseInt(lyricsStyle.marginTop) - 170) / 34);
			if (line < 0) {
				line = 0;
			} else if (line > lyrics.length - 1) {
				line = lyrics.length - 1;
			}
			lyricsTime_a[1].innerText = timeArray2[line];
		};
		document.onmouseup = function () {
			// Y1的作用是判断用户是否仍处于拖拽状态,若一秒后歌词位置仍等于Y1,则判断为非拖拽状态,但这样写有一个bug就是如果只是按住鼠标不进行拖拽,则也会判断为非拖拽状态,暂时想不到解决方法
			var lyrics_Y1 = parseInt(lyricsStyle.marginTop);
			setTimeout(function () {
				if (parseInt(lyricsStyle.marginTop) == lyrics_Y1) {
					lyricsMove = false;
					setLyrics(nowLine);
					lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
						‘none‘;
				}
			}, 1000);
			// 清除鼠标移动方法的同时也一定要清除鼠标弹起方法,不然每次点击页面都会调用这个方法
			document.onmousemove = null;
			document.onmouseup = null;
		};
		// 防止选中文字
		return false;
	};

	// 音量控制
	// 音量控制没什么好说的,需要注意的是volume的音量是从0-1,所以在设置音量时要将其除以100
	let volume_now = document.getElementsByClassName(‘volume-now‘)[0];
	let volume_back = document.getElementsByClassName(‘volume-back‘)[0];
	let volume_text = document.getElementsByClassName(‘volume-text‘)[0];
	let volume_a = document.getElementsByClassName(‘volume‘)[0];
	volume_back.onmousedown = function (e) {
		volume_now.style.width = e.offsetX + ‘px‘;
		myAduio.volume = e.offsetX / 100;
		volume_text.innerText = volume_now.clientWidth;
		volume_back.onmousemove = function (ev) {
			let volume = ev.offsetX;
			if (volume > 100) {
				volume = 100;
			}
			volume_now.style.width = volume + ‘px‘;
			myAduio.volume = volume / 100;
			volume_text.innerText = volume_now.clientWidth;
		};
		document.onmouseup = function () {
			// 如果音量为0,更换静音图片,否则更换非静音图片
			if (myAduio.volume == 0) {
				volume_a.style.backgroundImage = ‘url(../img/mute.png)‘;
			} else {
				volume_a.style.backgroundImage = ‘url(../img/volume.png)‘;
			}
			volume_back.onmousemove = null;
			document.onmouseup = null;
		};
		return false;
	};

	// 进度控制
	// 进度控制跟音量控制一样,只需要注意算法就好
	// 从之前的设置进度条进度我们可用知道,进度条的宽度=当前播放进度/歌曲总时长*进度条总长
	// 所以   当前播放进度=进度条宽度/进度条总长*歌曲总时长
	let progress_now = document.getElementsByClassName(‘progress-now‘)[0];
	let progress_bar = document.getElementsByClassName(‘progress-bar‘)[0];
	progress_bar.onmousedown = function (e) {
		progress_now.style.width = e.offsetX + ‘px‘;
		myAduio.pause();
		myAduio.currentTime =
			(e.offsetX * myAduio.duration) / progress_bar.clientWidth;
		setTimeText();
		progress_bar.onmousemove = function (ev) {
			let progress = ev.offsetX;
			if (progress > progress_bar.clientWidth) {
				progress = progress_bar.clientWidth;
			}
			progress_now.style.width = progress + ‘px‘;
			myAduio.currentTime =
				(progress * myAduio.duration) / progress_bar.clientWidth;
			setTimeText();
		};
		document.onmouseup = function () {
			myAduio.play();
			for (var i = 0; i < timeArray1.length; i++) {
				if (myAduio.currentTime < timeArray1[i]) {
					// 获取调整进度后当前处于哪一行歌词,假设我调整后的进度是1s,那么在数组中第一个大于1s的的上一个,就是当前行,所以需要-1
					// nowLine是i - 1 但是设置歌词位置却是 i - 2 的原因,因为我们的timeArray1是在开头多加了一个元素的,也就是说timeArray1数组比歌词数组多了一个元素,所以要再-1,而在lyricsRoll方法中,我是先设置计时器再将nowLine+1的,所以这里的nowLine要+1,那么总体结果就是,nowLine = i -1 , 设置歌词为 i - 2
					nowLine = i - 1;
					setLyrics(i - 2);
					timeInterval[nowLine] =
						timeArray1[nowLine + 1] - myAduio.currentTime;
					setPlay(true);
					break;
				}
			}
			progress_bar.onmousemove = null;
			document.onmouseup = null;
		};
		return false;
	};

	// 拖拽歌词调整进度,需要注意的也只是算出用户拖到了第几行而已,在拖拽歌词事件中(在上面)我们就已经将行数算出来了,这里直接调用就可用
	// 也说一下算法,因为我们是按照行来设置第一行歌词的marginTop的,那么反推过来就是
	// 行数=-(第一行歌词的marginTop-136)/34
	// 同样的,因为timeArray2数组多一个元素,所以显示拖拽歌词时显示的歌曲进度就要+1,我这里设置歌词位置是line - 1的原因是我在算行数的时候,将136改为了170,即我在算行数的时候就已经+1了
	let goto = document.getElementsByClassName(‘goto‘)[0];
	goto.onmouseup = function () {
		nowLine = line;
		myAduio.currentTime = timeArray1[line];
		setLyrics(line - 1);
		setPlay(true);

		lyricsMove = false;
		lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
			‘none‘;

		document.onmouseup = null;
	};
}

3.9设置静音

这个比较简单,就不说了

// 设置静音
function setMuted() {
	let volume_now = document.getElementsByClassName(‘volume-now‘)[0];
	let volume_text = document.getElementsByClassName(‘volume-text‘)[0];
	let volume_a = document.getElementsByClassName(‘volume‘)[0];
	if (myAduio.muted == true) {
		myAduio.muted = false;
		volume_a.style.backgroundImage = ‘url(../img/volume.png)‘;
		volume_now.style.width = myAduio.volume * 100 + ‘px‘;
		volume_text.innerText = myAduio.volume * 100;
	} else {
		myAduio.muted = true;
		volume_a.style.backgroundImage = ‘url(../img/mute.png)‘;
		volume_now.style.width = ‘0‘;
		volume_text.innerText = ‘0‘;
	}
}

到这里,我们的整个播放器就已经全部完成了

以下是完整代码

HTML

<!DOCTYPE html>

<html lang="zh-CN">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<link rel="stylesheet" href="css/music.css" />
		<link rel="icon" href="img/icon.jpg" />
		<title>音乐播放器</title>
	</head>
	<body>
		<!-- 音乐 -->
		<audio src="audio/韩安旭 - 不在.mp3" preload=""></audio>
		<!-- 背景板 -->
		<div class="background">
			<!-- 音乐区 -->
			<div class="music-background">
				<!-- 左侧图片 -->
				<div class="img-back">
					<img src="img/musicCover2.jpg" alt="韩安旭 - 不在" />
				</div>
				<!-- 右侧歌词 -->
				<div class="lyrics-back">
					<!-- 歌曲信息 -->
					<div class="div-title">
						<h1></h1>
						<p style="margin-right: 100px">
							专辑:
							<span></span>
						</p>
						<p>
							歌手:
							<span></span>
						</p>
					</div>
					<!-- 歌词信息 -->
					<div class="lyrics-time">
						<a href="#" class="goto"></a>
						<a href="#" class="goto-time">00:00</a>
					</div>
					<div class="div-lyrics"></div>
				</div>
			</div>
			<!-- 控制区 -->
			<div class="control-back">
				<!-- 进度条 -->
				<div class="progress-bar">
					<div class="progress-all"></div>
					<div class="progress-now"></div>
				</div>
				<span class="time">00:00/00:00</span>
				<!-- 控制按钮 -->
				<div class="control">
					<!-- 上一首、下一首、暂停播放 -->
					<div class="control-btn">
						<a href="#" class="up"></a>
						<a href="#" class="play-pause" onclick="setPlay()"></a>
						<a href="#" class="down"></a>
					</div>
					<!-- 播放模式、声音 -->
					<div class="control-right">
						<a href="#" class="mode"></a>
						<a href="#" class="volume" onclick="setMuted()"></a>
						<div class="volume-back">
							<div class="volume-all"></div>
							<div class="volume-now"></div>
						</div>
						<span class="volume-text">100</span>
					</div>
				</div>
			</div>
		</div>
		<script src="js/music.js"></script>
	</body>
</html>

CSS

* {
	margin: 0;
	padding: 0;
	user-select: none;
}

h1 {
	font-weight: 500;
}

a {
	color: #000;
	text-decoration: none;
}

/* 背景板 */
.background {
	width: 100vw;
	height: 100vh;
	background-color: #fff;
}

/* 歌词封面背景 */
.music-background {
	width: 1000px;
	height: calc(100vh - 200px);
	margin: 0 auto;
	overflow: hidden;
}

/* 封面背景 */
.img-back {
	width: 300px;
	padding: 0 50px;
	margin-top: 150px;
	margin-right: 50px;
	overflow: hidden;
	float: left;
}

.img-back img {
	width: 300px;
	height: 300px;
	border-radius: 20px;
}

/* 歌词背景 */
.lyrics-back {
	width: 550px;
	height: 100%;
	overflow: hidden;
	float: left;
}

/* 歌曲信息 */
.div-title {
	width: 100%;
	height: 100px;
	margin-top: 150px;
}

.div-title h1 {
	width: 100%;
	height: 50px;
}

.div-title p {
	height: 50px;
	display: inline-block;
	color: rgba(0, 0, 0, 0.5);
}

.div-title span {
	color: #000;
}

.div-lyrics {
	height: calc(100vh - 450px);
	overflow: hidden;
	position: relative;
}

.div-lyrics p {
	font-size: 15px;
	line-height: 34px;
}

/* 歌词进度 */
.lyrics-time {
	width: 650px;
	height: 34px;
	margin-top: 136px;
	margin-left: -50px;
	position: absolute;
	display: none;
}

.lyrics-time a {
	display: inline-block;
	position: absolute;
	display: none;
}

.goto {
	width: 20px;
	height: 20px;
	margin: 7px 15px;
	background: url(../img/play.png) no-repeat;
	background-position: 50% 50%;
	background-size: 20px;
}

.goto-time {
	width: 50px;
	height: 34px;
	margin-left: 550px;
	font-size: 13px;
	line-height: 34px;
	text-align: center;
	position: absolute;
	color: #5192fe;
}

/* 控制背景 */
.control-back {
	width: 100vw;
	height: 80px;
	bottom: 0;
	position: absolute;
	background-color: rgba(255, 255, 255, 0.8);
}

/* 进度条 */
.progress-bar {
	width: calc(100vw - 100px);
	margin: 5px 0;
	padding: 5px 0;
	cursor: pointer;
	float: left;
}

/* 当前播放进度 */
.progress-now {
	width: 0;
	height: 1px;
	margin-top: -1px;
	background-color: #5192fe;
}

/* 总播放进度 */
.progress-all {
	width: 100%;
	height: 1px;
	background-color: #dee2e6;
}

/* 播放进度 文本 */
.time {
	display: inline-block;
	width: 90px;
	height: 21px;
	margin-left: 5px;
	text-align: center;
	color: rgba(128, 130, 133, 0.8);
	cursor: default;
	overflow: hidden;
}

/* 控制按钮 */
.control {
	width: 100%;
	height: 30px;
	margin-top: 19px;
}

.control a {
	margin: 0 5px;
	display: inline-block;
}

.control a:hover {
	opacity: 50%;
}

.control-btn {
	width: 130px;
	height: 30px;
	margin: 0 auto;
}

/* 上一首 */
.up {
	width: 30px;
	height: 30px;
	background: url(../img/up.png) no-repeat;
	background-size: 20px;
	background-position: 50% 50%;
}

/* 暂停播放 */
.play-pause {
	width: 30px;
	height: 30px;
	background: url(../img/play.png) no-repeat;
	background-size: 30px;
	background-position: 50% 50%;
}

/* 下一首 */
.down {
	width: 30px;
	height: 30px;
	background: url(../img/down.png) no-repeat;
	background-size: 20px;
	background-position: 50% 50%;
}

/* 右侧控制按钮 */
.control-right {
	/* width: 180px; */
	height: 30px;
	margin-left: calc(50vw + 150px);
	margin-top: -30px;
	display: flex;
	align-items: center;
}

/* 播放模式 */
.mode {
	width: 30px;
	height: 30px;
	background: url(../img/sequence.png) no-repeat;
	background-size: 20px;
	background-position: left 50%;
	cursor: pointer;
}

/* 声音控制 */
.volume {
	width: 30px;
	height: 30px;
	background: url(../img/volume.png) no-repeat;
	background-size: 20px;
	background-position: left 50%;
	cursor: pointer;
}

.volume-back {
	padding: 5px 0;
	cursor: pointer;
}

.volume-all {
	width: 100px;
	height: 2px;
	background-color: #e5e5e5;
}

.volume-now {
	width: 100px;
	height: 2px;
	margin-top: -2px;
	max-width: 100px;
	background-color: #5192fe;
}

.volume-text {
	margin-left: 10px;
	font-size: 14px;
}

JS

var myAduio = document.getElementsByTagName(‘audio‘)[0];
var divLyrics = document.getElementsByClassName(‘div-lyrics‘)[0];
var divTitle = document.getElementsByClassName(‘div-title‘)[0];
var lyricsTime = document.getElementsByClassName(‘lyrics-time‘)[0];
var lyricsTime_a = lyricsTime.getElementsByTagName(‘a‘);
var progressTime = document.getElementsByClassName(‘time‘)[0];
var nowLine = 0;
var lyricsMove = false;
var playState = false;
var lyrics, lyricsStyle, lyricsFirst, rollT;
var timeArray1 = new Array();
var timeArray2 = new Array();
var timeInterval = new Array();

window.onload = function () {
	initialLyrics();
	lyricsStyle = getComputedStyle(lyricsFirst, null);
	setLyrics(0);
	setMouseEvent();
	setTimeText();
};

// 设置事件
function setMouseEvent() {
	// 歌词拖拽
	let lyrics_Y, line;
	divLyrics.onmousedown = function (e) {
		if (lyricsMove == false) {
			lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
				‘block‘;
			lyricsMove = true;
		}
		lyrics_Y = parseInt(lyricsStyle.marginTop);
		document.onmousemove = function (event) {
			lyricsFirst.style.marginTop =
				event.clientY - (e.clientY - lyrics_Y) + ‘px‘;
			line = Math.floor(-(parseInt(lyricsStyle.marginTop) - 170) / 34);
			if (line < 0) {
				line = 0;
			} else if (line > lyrics.length - 1) {
				line = lyrics.length - 1;
			}
			lyricsTime_a[1].innerText = timeArray2[line];
		};
		document.onmouseup = function () {
			var lyrics_Y1 = parseInt(lyricsStyle.marginTop);
			setTimeout(function () {
				if (parseInt(lyricsStyle.marginTop) == lyrics_Y1) {
					lyricsMove = false;
					setLyrics(nowLine);
					lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
						‘none‘;
				}
			}, 1000);
			document.onmousemove = null;
			document.onmouseup = null;
		};
		// 防止选中文字
		return false;
	};

	// 音量控制
	let volume_now = document.getElementsByClassName(‘volume-now‘)[0];
	let volume_back = document.getElementsByClassName(‘volume-back‘)[0];
	let volume_text = document.getElementsByClassName(‘volume-text‘)[0];
	let volume_a = document.getElementsByClassName(‘volume‘)[0];
	volume_back.onmousedown = function (e) {
		volume_now.style.width = e.offsetX + ‘px‘;
		myAduio.volume = e.offsetX / 100;
		volume_text.innerText = volume_now.clientWidth;
		volume_back.onmousemove = function (ev) {
			let volume = ev.offsetX;
			if (volume > 100) {
				volume = 100;
			}
			volume_now.style.width = volume + ‘px‘;
			myAduio.volume = volume / 100;
			volume_text.innerText = volume_now.clientWidth;
		};
		document.onmouseup = function () {
			if (myAduio.volume == 0) {
				volume_a.style.backgroundImage = ‘url(../img/mute.png)‘;
			} else {
				volume_a.style.backgroundImage = ‘url(../img/volume.png)‘;
			}
			volume_back.onmousemove = null;
			document.onmouseup = null;
		};
		return false;
	};

	// 进度控制
	let progress_now = document.getElementsByClassName(‘progress-now‘)[0];
	let progress_bar = document.getElementsByClassName(‘progress-bar‘)[0];
	progress_bar.onmousedown = function (e) {
		progress_now.style.width = e.offsetX + ‘px‘;
		myAduio.pause();
		myAduio.currentTime =
			(e.offsetX * myAduio.duration) / progress_bar.clientWidth;
		setTimeText();
		progress_bar.onmousemove = function (ev) {
			let progress = ev.offsetX;
			if (progress > progress_bar.clientWidth) {
				progress = progress_bar.clientWidth;
			}
			progress_now.style.width = progress + ‘px‘;
			myAduio.currentTime =
				(progress * myAduio.duration) / progress_bar.clientWidth;
			setTimeText();
		};
		document.onmouseup = function () {
			myAduio.play();
			for (var i = 0; i < timeArray1.length; i++) {
				if (myAduio.currentTime < timeArray1[i]) {
					nowLine = i - 1;
					setLyrics(i - 2);
					timeInterval[nowLine] =
						timeArray1[nowLine + 1] - myAduio.currentTime;
					setPlay(true);
					break;
				}
			}
			progress_bar.onmousemove = null;
			document.onmouseup = null;
		};
		return false;
	};

	let goto = document.getElementsByClassName(‘goto‘)[0];
	goto.onmouseup = function () {
		nowLine = line;
		myAduio.currentTime = timeArray1[line];
		setLyrics(line - 1);
		setPlay(true);

		lyricsMove = false;
		lyricsTime_a[0].style.display = lyricsTime_a[1].style.display = lyricsTime.style.display =
			‘none‘;

		document.onmouseup = null;
	};
}

// 设置播放状态
function setPlay(state) {
	var play_pause = document.getElementsByClassName(‘play-pause‘)[0];
	if (state == null) {
		state = myAduio.paused;
	}
	clearTimeout(rollT);
	if (state == true) {
		myAduio.play();
		play_pause.style.backgroundImage = ‘url(../img/pause.png)‘;
		playState = true;
		setTimeText();
		lyricsRoll();
		setProgress();
	} else {
		myAduio.pause();
		play_pause.style.backgroundImage = ‘url(../img/play.png)‘;
		playState = false;
		timeInterval[nowLine] = timeArray1[nowLine + 1] - myAduio.currentTime;
	}
}

// 设置音量
function setVolume(volume) {
	myAduio.volume = volume;
}

// 设置静音
function setMuted() {
	let volume_now = document.getElementsByClassName(‘volume-now‘)[0];
	let volume_text = document.getElementsByClassName(‘volume-text‘)[0];
	let volume_a = document.getElementsByClassName(‘volume‘)[0];
	if (myAduio.muted == true) {
		myAduio.muted = false;
		volume_a.style.backgroundImage = ‘url(../img/volume.png)‘;
		volume_now.style.width = myAduio.volume * 100 + ‘px‘;
		volume_text.innerText = myAduio.volume * 100;
	} else {
		myAduio.muted = true;
		volume_a.style.backgroundImage = ‘url(../img/mute.png)‘;
		volume_now.style.width = ‘0‘;
		volume_text.innerText = ‘0‘;
	}
}

// 歌词回弹
function lyricsRebound(lyricsTop) {
	if (parseInt(lyricsStyle.marginTop) != nowLine * -34 + 136) {
		if (lyricsTop == null) {
			lyricsTop = nowLine * -34 + 136;
		}
		let lyrics_animation = lyricsFirst.animate(
			[
				{
					marginTop: lyricsStyle.marginTop,
				},
				{
					marginTop: lyricsTop + ‘px‘,
				},
			],
			{
				duration: 500,
			}
		);
		lyrics_animation.addEventListener(
			‘finish‘,
			function () {
				lyricsFirst.style.marginTop = lyricsTop + ‘px‘;
			},
			false
		);
	}
}

// 初始化歌词
function initialLyrics() {
	let sp = divTitle.getElementsByTagName(‘span‘)[0];
	let ar = divTitle.getElementsByTagName(‘span‘)[1];
	let ti = divTitle.getElementsByTagName(‘h1‘)[0];
	let lyricsData, timeString;
	let lyricsArray = new Array();
	// 清除数组
	timeArray1.splice(0, timeArray1.length);
	timeArray2.splice(0, timeArray2.length);
	lyricsArray.splice(0, lyricsArray.length);
	// 按相同格式放入歌词更换歌曲即可达到相同效果
	lyricsData =
		‘[ar]韩安旭\n[ti]不在\n[sp]不在\n[00:00.74]韩安旭 - 不在\n[00:01.76]词:尤雅琪\n[00:02.76]曲:胜屿\n[00:15.62]我累了就紧紧锁住情绪\n[00:18.11]不再放任它堆积\n[00:22.14]我痛了就静静屏住呼吸\n[00:26.02]不给想念留余地\n[00:28.88]只是下雨时会委屈\n[00:32.80]只是想起你会哭泣\n[00:36.77]没关系 真没关系\n[00:44.28]我终于学会一个人弹琴\n[00:47.12]只是弹琴没有你\n[00:49.29]我终于学会一个人做梦\n[00:54.85]只是做梦没有你\n[00:57.73]我依旧像从前粗心\n[01:01.09]时常会忘记星期几\n[01:05.00]却始终忘不掉你看我的眼睛\n[01:11.71]穿过了熙攘的人海\n[01:15.11]想找谁能把你取代\n[01:19.62]复制你曾给过我的\n[01:21.44]那种宠爱\n[01:26.32]掏空了回忆的脑海\n[01:30.75]寂寞却狠狠扑过来\n[01:33.69]措手不及 无法躲开\n[01:41.52]我承认是我太依赖\n[01:44.92]像个不懂事的小孩\n[01:48.35]挥霍掉我们的未来\n[01:51.22]才醒过来\n[01:55.15]我承认后悔了伤害\n[01:59.06]抛开你的好我的坏\n[02:02.14]直到如今学会忍耐 你不在\n[02:26.95]我终于学会一个人弹琴\n[02:29.33]只是弹琴没有你\n[02:33.26]我终于学会一个人做梦\n[02:36.64]只是做梦没有你\n[02:39.53]我依旧像从前粗心\n[02:42.90]时常会忘记星期几\n[02:46.82]却始终忘不掉你看我的眼睛\n[02:53.62]穿过了熙攘的人海\n[02:57.09]想找谁能把你取代\n[03:00.98]复制你曾给过我的\n[03:05.43]那种宠爱\n[03:08.25]掏空了回忆的脑海\n[03:11.67]寂寞却狠狠扑过来\n[03:15.56]措手不及 无法躲开\n[03:22.49]我承认是我太依赖\n[03:26.37]像个不懂事的小孩\n[03:30.38]挥霍掉我们的未来\n[03:33.80]才醒过来\n[03:37.81]我承认后悔了伤害\n[03:41.29]抛开你的好我的坏\n[03:44.73]直到如今学会忍耐 你不在‘;
	// 文本.split(‘分隔符‘),用于分割文本
	lyricsArray = lyricsData.split(‘\n‘);
	// 添加歌曲信息
	ar.innerText = lyricsArray[0].split(‘]‘)[1];
	ti.innerText = lyricsArray[1].split(‘]‘)[1];
	sp.innerText = lyricsArray[2].split(‘]‘)[1];
	// 添加歌词
	for (var i = 3; i < lyricsArray.length; i++) {
		if (i == 3) {
			divLyrics.innerHTML +=
				‘<p style="margin-top: 100%;color:#5192fe;">‘ +
				lyricsArray[i].split(‘]‘)[1] +
				‘</p>‘;
		} else {
			divLyrics.innerHTML +=
				‘<p>‘ + lyricsArray[i].split(‘]‘)[1] + ‘</p>‘;
		}
	}

	// 获取后续需要使用的变量
	lyricsFirst = divLyrics.getElementsByTagName(‘p‘)[0];
	lyrics = divLyrics.getElementsByTagName(‘p‘);

	// 计算每局歌词所在的秒数
	timeArray1.push(0);
	for (var i = 0; i < lyrics.length; i++) {
		timeString = lyricsArray[i + 3].substring(1, 9).split(‘:‘);
		timeArray1.push(
			parseFloat(timeString[0]) * 60 + parseFloat(timeString[1])
		);
	}

	// 计算时间间隔,将时间从秒数改为分钟+秒数
	for (var i = 0; i < timeArray1.length - 1; i++) {
		timeInterval[i] = timeArray1[i + 1] - timeArray1[i];
		if (Math.floor(timeArray1[i] % 60) < 10) {
			timeArray2.push(
				Math.floor(timeArray1[i] / 60) +
					‘:0‘ +
					Math.floor(timeArray1[i] % 60)
			);
		} else {
			timeArray2.push(
				Math.floor(timeArray1[i] / 60) +
					‘:‘ +
					Math.floor(timeArray1[i] % 60)
			);
		}
	}
}

// 设置歌词位置
function setLyrics(line) {
	for (let i = 0; i < lyrics.length; i++) {
		lyrics[i].style.color = ‘#000‘;
	}
	lyrics[line].style.color = ‘#5192fe‘;
	let lyrics_animation = lyrics[0].animate(
		[
			{
				marginTop: lyricsStyle.marginTop,
			},
			{
				marginTop: line * -34 + 136 + ‘px‘,
			},
		],
		{
			duration: 100,
		}
	);
	lyrics_animation.addEventListener(
		‘finish‘,
		function () {
			lyrics[0].style.marginTop = line * -34 + 136 + ‘px‘;
		},
		false
	);
}

// 歌词滚动
function lyricsRoll() {
	rollT = setTimeout(function () {
		if (nowLine < lyrics.length && myAduio.paused == false) {
			if (lyricsMove == false) {
				setLyrics(nowLine);
			}
			nowLine += 1;
			lyricsRoll();
		}
	}, timeInterval[nowLine] * 1000);
}

// 设置进度文本
function setTimeText() {
	var nowTime = myAduio.currentTime;
	var allTime = myAduio.duration;
	// 计算时间,若为个位数,补0
	if (Math.floor(nowTime % 60) < 10) {
		nowTime = Math.floor(nowTime / 60) + ‘:0‘ + Math.floor(nowTime % 60);
	} else {
		nowTime = Math.floor(nowTime / 60) + ‘:‘ + Math.floor(nowTime % 60);
	}
	if (Math.floor(allTime % 60) < 10) {
		allTime = Math.floor(allTime / 60) + ‘:0‘ + Math.floor(allTime % 60);
	} else {
		allTime = Math.floor(allTime / 60) + ‘:‘ + Math.floor(allTime % 60);
	}
	progressTime.innerText = nowTime + ‘/‘ + allTime;
	// 每0.1秒执行一次
	if (myAduio.paused == false) {
		setTimeout(setTimeText, 100);
	}
}

// 设置进度条进度
function setProgress() {
	let progress_now = document.getElementsByClassName(‘progress-now‘)[0];
	let progress_bar = document.getElementsByClassName(‘progress-bar‘)[0];
	let progress = Math.floor(
		(myAduio.currentTime / myAduio.duration) * progress_bar.clientWidth
	);
	progress_now.style.width = progress + ‘px‘;
	if (myAduio.paused == false) {
		setTimeout(setProgress, 100);
	}
}

// 获取网页属性
function getDocument(attribute) {
	if (attribute == ‘sT‘) {
		return document.documentElement.scrollTop;
	} else if (attribute == ‘sL‘) {
		return document.documentElement.scrollLeft;
	} else if (attribute == ‘sH‘) {
		return document.documentElement.scrollHeight;
	} else if (attribute == ‘sW‘) {
		return document.documentElement.scrollWidth;
	} else if (attribute == ‘cH‘) {
		return document.documentElement.clientHeight;
	} else if (attribute == ‘cW‘) {
		return document.documentElement.clientWidth;
	}
}

其中JS中,获取页面属性跟歌词回弹是没有用到的,获取页面属性我写是为了方便,但结果发现没用上,歌词回弹是后来发现直接用设置歌词方法来进行回弹即可,也就是说歌词回弹写了是多余的

使用HTML+CSS+JS做一个音乐播放器

上一篇:.NET并发编程-数据结构不可变性


下一篇:EclipseHTML/JS/CSS/JS 代码自动提示