JavaScript + Audio API自制简易音乐播放器(详细完整版、小白都能看懂)

JavaScript + Audio API自制简易音乐播放器(详细完整版)

**

音乐播放器的功能清单如下:

**
1.点击暂停按钮,歌曲暂停
2.点击播放按钮,歌曲播放
3.单曲循环与取消单曲循环
4.当播放到列表最后一首歌曲时,点击下一首自动切换到列表中的第一首
5.当播放到列表第一首歌曲时,点击上一首自动切换到列表中的最后一首
6.一键静音与非静音
7.增大减小音量(既可通过鼠标点击操作,也可通过键盘上下键操作)
8.下一首、上一首
9.快进、快退
10.进度条随这音乐播放实时变化
11.歌曲已播放时长实时变化
12.点击进度条区域可以进行快进快退,已播放时长和进度条的进度也同步更新
13.鼠标点击拖动进度条的红点(小方块)可以进行快进快退,已播放时长和进度条的进度也同步更新

首先来看一下效果图:
音乐播放器
在这里插入图片描述
这是我的目录结构:
在这里插入图片描述

JavaScript部分的难点:
1.多媒体事件的运用
2.获取Dom对象
3.设置flag记录true false的小技巧,来达到在同一个元素上点击,出现不同的效果
4.鼠标事件的灵活运用
5.通过Dom对象动态修改样式
6.设置定时器
7.键盘事件

CSS部分难点:
1.渐变色
2.pointer-events: none;可以让某个元素实现类似于海市蜃楼的效果,具体理解为,你可以看的到某个元素,但是你无法摸的着。
3.相对定位
4.绝对定位
5.flex弹性盒子布局
6.精灵图background属性的灵活运用
7.属性zoom: 0.2; 强制缩放
zoom牵一发动全身,zoom:0.5后 ,width和height都会变成原来的一半 ;
而transform: scale(0.5) div height200px,width:200px, scale(0.5)即为缩小为原来的一半时,他的height和width还是200px, 只不过里面的元素缩小了而已。

page.js部分的代码如下:

var arrys = [
	"./songs/晴天 周杰伦.mp3",
	"./songs/时间停了 鹿晗.mp3",
	"./songs/光辉岁月 Beyon.mp3",
	"./songs/栀子花开 何炅.mp3",
	"./songs/纸短情长 烟把儿乐队.mp3"
];

var audio = document.createElement("audio");
audio.src = arrys[0];
// 多媒体(Media)事件:
// canplaythrough 事件在视频/音频(audio/video)可以正常播放且无需停顿和缓冲时触发。
// durationchange 事件在视频/音频(audio/video)的时长发生变化时触发。
// pause 事件在视频/音频(audio/video)暂停时触发。
// play 事件在视频/音频(audio/video)开始播放时触发。
// volumechange 事件在音量发生改变时触发。
// ended 事件在视频/音频(audio/video)播放结束时触发。
// error 事件在视频/音频(audio/video)数据加载期间发生错误时触发。
// canplay 事件在用户可以开始播放视频/音频(audio/video)时触发。 
// timeupdate 事件在当前的播放位置发送改变时触发。


audio.addEventListener("canplaythrough", function() {
	console.log('music ready');
}, false);
audio.addEventListener("timeupdate", showTime, true);

function showTime() {
	duration = formatTime(audio.duration);
	currenttime = formatTime(audio.currentTime);
	document.getElementById('totaltime').innerHTML = duration.M + ':' + duration.S;
	document.getElementById('currenttime').innerHTML = currenttime.M + ':' + currenttime.S;
	//获取当前播放的百分比  当前进度/总进度
	var percent = audio.currentTime / audio.duration
	//拼接进度条的width
	var swidth = (percent * 255) + "px";

	//设置进度条的播放进度
	document.getElementById("bar").style.width = swidth;
	document.getElementById("dot").style.left = swidth;
}
// 播放
function aPlay() {
	audio.play();
}
// 暂停
function aPause() {
	audio.pause();
}
// 快进
function go() {
	audio.currentTime += 10;
	audio.play();
	runToPause();
}
// 快退
function back() {
	audio.currentTime -= 10;
	audio.play();
	runToPause();
}

// 将播放图标切换为暂停图标
function runToPause(){
	runDom[0].style.display = 'none';
	pauseDom[0].style.display = 'inline-block';
}
// 将暂停图标切换为播放图标
function PauseToRun(){
	runDom[0].style.display = 'inline-block';
	pauseDom[0].style.display = 'none';
}

quietDom = document.getElementsByClassName('quiet');
noquietDom = document.getElementsByClassName('noquiet');
// 将静音图标切换为非静音图标
function quietToNo(){
	quietDom[0].style.display = 'none';
	noquietDom[0].style.display = 'inline-block';
}

// 将非静音图标切换为静音图标
function noToquiet(){
	quietDom[0].style.display = 'inline-block';
	noquietDom[0].style.display = 'none';
}


// 增大音量
function add() {
	audio.volume != 1 ? audio.volume += 0.1 : 1;
	console.log(audio.volume);
	if (audio.volume >= 0.001) {
		quietToNo();
		console.log('noquiet')
	}
}

// 减小音量
function subtract() {
	audio.volume != 0 ? audio.volume -= 0.1 : 0;
	console.log(audio.volume);
	if (audio.volume <= 0.001) {
		noToquiet();
		console.log('quiet')
	}
}

// 静音
var qFlag = 0; // 是否静音
function isquiet() {
	qFlag = !qFlag;
	// if(qFlag){
	// 	audio.volume = 0;	
	// 	console.log(audio.volume);
	// }else{
	// 	audio.volume = 0.5;
	// }	
	audio.volume = !audio.volume;

}
// 静音图标切换为非静音图标
function quiet() {
	quietToNo();
	isquiet();
}

// 非静音图标切换为静音图标
function noquiet() {
	noToquiet();
	isquiet();
}

// 时间格式转换
function formatTime(seconds) {
	var h = 0,
		i = 0,
		s = Math.floor(seconds);
	h = Math.floor(s / 3600);
	i = Math.floor((s % 3600) / 60);
	s = s % 3600 % 60;

	return {
		H: h = h < 10 ? "0" + h : h,
		M: i = i < 10 ? "0" + i : i,
		S: s = s < 10 ? "0" + s : s
	};
};

//设置播放源
var currMp3 = arrys[0];
//上一曲,并实现循环播放
function prev() {
	tmpMp3 = "";
	arrys.forEach(function(item, index) {
		// 通过循环找到与当前播放的音乐相同的那一个item,目的是为了拿到当前的index
		if (item == currMp3) {
			if (index == 0) {
				tmpMp3 = arrys[arrys.length - 1];
			} else {
				//下一个
				tmpMp3 = arrys[index - 1];
			}
			console.log(tmpMp3)
			audio.src = tmpMp3;
			setTimeout(function() {
				audio.play()
				currMp3 = tmpMp3;
			}, 500)
			return;
		}
	})
	run(); // 把播放图标切换成暂停图标并播放音乐
}

// 下一曲,并实现循环播放
function next() {
	tmpMp3 = "";
	arrys.forEach(function(item, index) {
		if (item == currMp3) { // 当找到当前播放的歌曲时,进入if代码执行块
			if ((index + 1) == arrys.length) {
				//说明是最后一个
				tmpMp3 = arrys[0];
			} else {
				//下一个
				tmpMp3 = arrys[index + 1];
			}
			console.log(tmpMp3)
			audio.src = tmpMp3;
			setTimeout(function() { // 设置定时器,在点击下一曲按钮时生效,
				audio.play(); // play() 方法开始播放当前的音频或视频。
				currMp3 = tmpMp3; // 将当前播放音乐的路径更新到currMp3中保存
			}, 500)
			return;
		}
	})
	run(); // 把播放图标切换成暂停图标,并播放音乐
}

var flag = 0; // 是否点击了单曲循环按钮,点了为1,没点为0
// 当前歌曲播放完后,自动切换下一首
audio.addEventListener('ended', function() {
	if (flag) {
		arrys.forEach(function(item, index) {
			if (item == currMp3) {
				tmpMp3 = arrys[index]
			}
			setTimeout(function() {
				audio.play()
				currMp3 = tmpMp3;
			}, 500)
		})
	} else {
		next();
	}
}, false);

// 实现单曲循环
function circle() {
	console.log('单曲循环')
	flag = !flag; // 是否点击了单曲循环按钮,点了为1,没点为0
	console.log(flag);
}

document.onkeyup = function(event) { //键盘事件
	var vol = 0.1; //1代表100%音量,每次增减0.1
	var time = 10; //单位秒,每次增减10秒
	// console.log("keyCode:" + event.keyCode);
	console.log("volume" + audio.volume);
	var e = event || window.event || arguments.callee.caller.arguments[0];


// 键盘事件:
// 属性 描述 DOM
// keydown 某个键盘按键被按下。
// keypress 某个键盘按键被按下并松开。
// keyup 某个键盘按键被松开。

	//实现键盘按上下键控制音乐的音量,按左右键控制音乐的快进快退
	if (e && e.keyCode === 38) {
		// 按 向上键
		audio.volume !== 1 ? audio.volume += vol : 1;
		if (audio.volume >= 0.001) {
			quietToNo();
			console.log('noquiet')
		}
		return false;

	} else if (e && e.keyCode === 40) {
		// 按 向下键
		audio.volume !== 0 ? audio.volume -= vol : 1;
		if (audio.volume <= 0.001) {
			noToquiet();
			console.log('quiet')
		}
		return false;

	} else if (e && e.keyCode === 37) {
		// 按 向左键
		audio.currentTime !== 0 ? audio.currentTime -= time : 1;
		return false;

	} else if (e && e.keyCode === 39) {
		// 按 向右键
		audio.volume !== audio.duration ? audio.currentTime += time : 1;
		return false;

	} else if (e && e.keyCode === 32) {
		// 按空格键 判断当前是否暂停
		audio.paused === true ? audio.play() : audio.pause();
		if (audio.paused === false) {
			runToPause();
		} else {
			pauseToRun();
		}
		return false;
	}

};
runDom = document.getElementsByClassName('run');
pauseDom = document.getElementsByClassName('pause');
// 点击播放按钮切换为暂停按钮
function run() {
	runToPause();
	aPlay();
}
// 暂停按钮切换为播放按钮
function pause() {
	PauseToRun();
	aPause();
}

// 鼠标事件:
// onclick 当用户点击某个对象时调用的事件句柄。
// ondblclick 当用户双击某个对象时调用的事件句柄。
// onmousedown 鼠标左键被按下。
// onmouseenter 当鼠标指针移动到元素上时触发。
// onmouseleave 当鼠标指针移出元素时触发
// onmousemove 鼠标被移动。
// onmouseover 鼠标移到某元素之上。
// onmouseout 鼠标从某元素移开。
// onmouseup 鼠标左键被松开。


window.onload = function() {
	var scrollDom = document.getElementById('scroll');
	var barDom = document.getElementById('bar');
	var dotDom = document.getElementById('dot');
    // 鼠标左键被按下。
	scrollDom.onmousedown = function(event) {
		// console.log("111" + event.offsetX);
		// 鼠标被移动
		scrollDom.onmousemove = function(event) {
			// console.log(event.offsetX);
			// console.log("offsetLeft" + event.offsetLeft)
			barDom.style.width = event.offsetX + "px";
			dotDom.style.left = (event.offsetX) + "px";
			pause();
		}
	}
	// 鼠标移到某元素上
	scrollDom.onmouseover = function() {
		scrollDom.onmousemove = null;
	}
	// 鼠标左键被松开
	scrollDom.onmouseup = function(e) {
		scrollDom.onmousemove = null; //鼠标左键松开后不做任何操作
		currentX = e.offsetX;
		var oWidth = scrollDom.offsetWidth; // 元素整体宽度 :边框+内容区
		var cWidth = scrollDom.clientWidth; // 元素内容区宽度 :内容区
		var percents = (currentX / cWidth).toFixed(2);
		// console.log(percents + '%!')
		audio.currentTime = audio.duration * percents;
		run();
	}
	scrollDom.onclick = function(e) {
		console.log(e.offsetX);
		currentX = e.offsetX;
		barDom.style.width = e.offsetX + "px";
		dotDom.style.left = (e.offsetX) + "px";
		var oWidth = scrollDom.offsetWidth; // 元素整体宽度 :边框+内容区
		var cWidth = scrollDom.clientWidth; // 元素内容区宽度 :内容区
		var percents = (currentX / cWidth).toFixed(2);
		// console.log(percents + '%')
		// console.log(audio.duration * percents)
		// console.log(formatTime(audio.duration * percents))
		audio.currentTime = audio.duration * percents;
	}

}

index.html部分的代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>简易音乐播放器</title>
		<link rel="stylesheet" href="./css/style.css">
		<script src="./js/page.js"></script>
	</head>
	<body>
		<div id="all">
			<div class="speed">
				<div class="back" οnclick="back()" id="back" title="快退"></div>
				<div class="go" οnclick="go()" id="go" title="快进"></div>
			</div>
			<div class="players">
				<div class="container clearfix">
					<div class="left clearfix">
						<div class="prev" οnclick="prev()" title="上一首"></div>
						<div class="run" οnclick="run();" title="播放"></div>
						<div class="pause" οnclick="pause();" title="暂停"></div>
						<div class="next" οnclick="next()" title="下一首"></div>
					</div>
					<div class="middle">
						<div class="scroll" id="scroll">
							<div class="bar" id="bar">
								<div class="dot" id="dot"></div>
							</div>
						</div>
						<div class="music_detail">
							<div id="currenttime">00:00</div>
							<div class="line"> / </div>
							<div id="totaltime">00:00</div>
						</div>
					</div>
					<div class="right">
						<div class="circle" οnclick="circle()" title="单曲循环"></div>
						<div class="quiet" οnclick="quiet()" id="quiet" title="取消静音"></div>
						<div class="noquiet" οnclick="noquiet()" id="noquiet" title="静音"></div>
						<div class="verticle">
							<div class="add" οnclick="add()" id="add" title="增加音量"></div>
							<div class="subtract" οnclick="subtract()" id="subtract" title="减小音量"></div>
						</div>
					</div>

				</div>
			</div>
		</div>
	</body>
</html>


style.css部分的代码如下:

#progressBar {
	width: 80%;
	height: 32%;
	background: #e9e9e9;
	position: relative;
}

#playProgressBar {
	position: absolute;
	top: 0;
	left: 0;
	background: #20bfd8;
	height: 100%;
	width: 100%;
}

#ptxt {
	width: 100%;
	height: 30px;
	text-align: center;
	font-size: 16px;
	line-height: 30px;
	z-index: 10;
	position: absolute;
}

* {
	margin: 0;
	padding: 0;
}

body {
	margin: 0 auto;
}
.speed{
	display: flex;
	align-items: center;
	justify-content: center;
}
#all{
	margin: 200px;
}

.clearfix:after {
	content: '';
	display: block;
	visibility: none;
	clear: both;
}

/* 播放图标 */
.run {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -267px -20px;
	zoom: 0.3;

}

/* float: left; */
/* zoom牵一发动全身,zoom:0.5后 ,width和height都会变成原来的一半 */
/*而transform: scale(0.5) div height200px,width:200px, scale(0.5)即为缩小为原来的一半时,他的height和width还是200px, 只不过里面的元素缩小了而已。 */


/* 暂停图标 */
.pause {
	display: none;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -517px -517px;
	zoom: 0.3;
}

/* zoom牵一发动全身,zoom:0.5后 ,width和height都会变成原来的一半 */
/*而transform: scale(0.5) div height200px,width:200px, scale(0.5)即为缩小为原来的一半时,他的height和width还是200px, 只不过里面的元素缩小了而已。 */


/* 下一首图标 */
.next {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -765px -266px;
	zoom: 0.2;
}

/* 上一首图标 */
.prev {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -14px -271px;
	zoom: 0.2;
}

/* 单曲循环图标 */
.circle {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -514px -23px;
	zoom: 0.2;
}

/* 增大音量图标 */
.add {
	display: inline-block;
	width: 90px;
	height: 90px;
	background-image: url(../img/voice.jpg);
	background-position: -163px -125px;
	zoom: 0.25;
}

/* 减小音量图标 */
.subtract {
	display: inline-block;
	width: 90px;
	height: 90px;
	background-image: url(../img/voice.jpg);
	background-position: -37px -125px;
	zoom: 0.25;
}

/* 静音图标 */
.quiet {
	display: none;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -517px -762px;
	zoom: 0.2;
}

/* 非静音图标 */
.noquiet {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -20px -762px;
	zoom: 0.2;
}

/* 快进图标 */
.go {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -515px -268px;
	zoom: 0.2;
}

/* 快退图标 */
.back {
	display: inline-block;
	width: 220px;
	height: 217px;
	background-image: url(../img/icons.jpg);
	background-position: -268px -268px;
	zoom: 0.2;
}

.players {
	box-sizing: border-box;
	width: 770px;
	height: 110px;
	background-image: linear-gradient(#436881, #ea9e0d);
	padding: 13px 0;
	border-radius: 25px 10px 25px 10px;
	/* 左上角,右上角,右下角,左下角 */
	margin: 0 auto;

}

.container {
	width: 96%;
	height: 97%;
	background-color: white;
	margin: 0 auto;
	display: flex;
	justify-content: space-around;
}

.left {
	width: 23%;
	height: 100%;
	display: flex;
	justify-content: space-around;
	align-items: center;
}

.middle {
	width: 53%;
	height: 100%;
	align-items: center;
	display: flex;
	padding: 20px;
	box-sizing: border-box;
}

.right {
	width: 16%;
	height: 100%;
	display: flex;
	justify-content: space-around;
	align-items: center;
}

.verticle {
	width: 15%;
	align-items: center;
	height: 69%;
}

.music_detail {
	display: flex;

}

#currenttime {
	font-size: 13px;
	line-height: 35px;
	margin-left: 20px;
}

#totaltime {
	font-size: 13px;
	line-height: 35px;
}

.line {
	font-size: 13px;
	line-height: 35px;
}
.scroll{
	width: 500px;
	height: 13px;
	background-color: gray;
}
.bar{
	width: 0px;
	height: 13px;
	background-color: aquamarine;
	position: relative;
	pointer-events: none;/* pointer-events: none; 可以让某个元素实现类似于海市蜃楼的效果,具体理解为,你可以看的到某个元素,但是你无法摸的着。 */
	cursor: move;
}
.dot{
	width: 5px;
	height: 13px;
	background-color: red;
	position: absolute;
	left: 0px;
	top: 0px;
}

原创文章 14 获赞 27 访问量 1126

猜你喜欢

转载自blog.csdn.net/weixin_44827418/article/details/105557833