个人小作品之迷你音乐播放器(移动端)

时间:2021-10-03 10:12:32

关于viewport


viewport是用户网页的可视区域,中文可称为“可视区”。
手机浏览器是将页面放在一个虚拟的窗口(viewport)中,通常这个窗口比屏幕宽,这样就不用把每个页面都挤在一个窗口中,用户通过平移和缩放来查看页面的不同的部分。


设置viewport

一个常用于针对移动页面优化过的页面的viewport meta 标签如下:
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">

其中:
  • width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
  • height:和 width 相对应,指定高度。
  • initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
  • maximum-scale:允许用户缩放到的最大比例
  • minimum-scale:允许用户缩放到的最小比例

本作品源代码GitHub:点击查看本作品源代码


开始制作播放器

播放器的效果图为:
个人小作品之迷你音乐播放器(移动端)


本次关于移动端的页面制作采用rem为单位。
rem:相对单位,相对于根目录<html>的font-size,根据设备的宽度自动改变

HTML部分的布局:使用HTML5标签进行布局
<!doctype html>
<html lang="zh-en">
<head>
<meta charset="utf-8">
<title>迷你音乐播放器</title>
<link rel="stylesheet" href="css/style.css">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
</head>
<body>
<header>
<h3 class="musicTitle"></h3>
</header>
<section class="singer">
<div>
<img src="images/tx.jpg">
</div>
</section>
<!-- 进度条部分 -->
<section class="progress">
<div class="bg"></div>
<div class="bar"></div>
</section>
<!-- 按钮部分 -->
<section class="btn">
<div class="prev iconfont"></div>
<div class="play iconfont"></div>
<div class="pause iconfont"></div>
<div class="next iconfont"></div>
</section>
<!-- 音频播放部分 -->
<audio src="mp3/" id="myMusic"></audio>

<script src="js/js.js"></script>
</body>
</html>


其中:
  • 进度条原理:就是不断改变 进度条的背景宽度 来 实现进度条的颜色改变部分。

<!-- 进度条部分 -->
<section class="progress">
<div class="bg"></div>
<div class="bar"></div>
</section>



CSS部分:
在实现进度条功能时:
  • 不断改变 进度条的背景宽度 来 实现 进度条颜色部分。
  • 对于小滑块部分,使用CSS3中的tranform: translate();属性来代替定位属性。
transform: translate(0rem, -.15rem); /* 代替绝对定位 */

分别为水平方向、垂直方向上的偏移。

  • 对于按钮部分,是使用 阿里图标 来代替图片,称为 IcomFont图标。
如:
个人小作品之迷你音乐播放器(移动端)

在HTML中输入对应的代码就相对应按钮,如:输入“&#xe6de”就相当于“上一曲按钮”。
使用这种图标分三个步骤:使用之前需要下载图标文件:阿里矢量图标管网,下载完成后:将里面的文件保存在一个文件夹里面,接着:
  • 第一步,使用font-face声明字体:
@font-face {
font-family: 'iconfont';
src: url('../iconfont/iconfont.eot');
src: url('../iconfont/iconfont.eot?#iefix') format('embedded-opentype'),
url('../iconfont/iconfont.woff') format('woff'),
url('../iconfont/iconfont.ttf') format('truetype'),
url('../iconfont/iconfont.svg#iconfont') format('svg');
}

其中,"font-family"为自定义的字体名称,注:src、url属性路径要正确。

  • 第二步,定义使用iconfont的样式:
.iconfont{
font-family:"iconfont" !important;
font-size: 1.5rem;
font-style: normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
color: #fff;
}


  • 第三步,挑选相应图标并获取相应字体编码,应用于页面
<div class="prev iconfont"></div>
<div class="play iconfont"></div>
<div class="pause iconfont"></div>
<div class="next iconfont"></div>

效果:
个人小作品之迷你音乐播放器(移动端)

注意:在布局时,需要先隐藏一个播放按钮。


CSS部分代码为:
* {
padding: 0;
margin: 0;
}


body {
background: url("../images/bg.jpg");
}


header {
width: 100%;
height: 2rem;
text-align: center;
color: #fff;
}

/* 自定义字体,阿里图标 */
@font-face {
font-family: 'iconfont';
src: url('../iconfont/iconfont.eot');
src: url('../iconfont/iconfont.eot?#iefix') format('embedded-opentype'),
url('../iconfont/iconfont.woff') format('woff'),
url('../iconfont/iconfont.ttf') format('truetype'),
url('../iconfont/iconfont.svg#iconfont') format('svg');
}

.iconfont{
font-family:"iconfont" !important;
font-size: 1.5rem;
font-style: normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
color: #fff;
}


header h3 {
font-size: 0.5rem;
line-height: 1.3rem;
}


header p {
font-size: 0.3rem;
}


.singer {
width: 8rem;
height: 8rem;
border: 1px solid #fff;
margin: auto;
border-radius: 50%;
}

.singer div {
width: 7.6rem;
height: 7.6rem;
margin: .2rem;
border-radius: 50%;
background: rgba(255, 255, 255, .5);
}

.rotate {
animation: rot 10s linear infinite;
}

@keyframes rot {
to {
transform: rotate(360deg);
}
}

.singer div img {
width: 7rem;
height: 7rem;
border-radius: 50%;
margin: 0.3rem;
}


.progress {
width: 9rem;
height: 0.1rem;
background: #c03;
margin: 1rem auto;
}


.bg {
width: 0;
height: 0.1rem;
background: #0f9
}


.bar {
width: .2rem;
height: .2rem;
background: blue;
border-radius: 50%;
transform: translate(0rem, -.15rem); /* 代替绝对定位 */
}


.btn {
width: 8rem;
margin: auto;
}

.btn div {
float: left;
margin: .5rem;
}


.pause {
display: none;
}




JS部分:

播放器功能的实现:
  • 点击按钮实现播放/暂停功能。

先获取表示播放和暂停功能的按钮:
var oPlay = document.getElementsByClassName("play")[0];
var oPause = document.getElementsByClassName("pause")[0];

点击实现播放/暂停:

/* 点击实现播放功能 */
oPlay.onclick = function () {
myMusic.play();
oPause.style.display = "block";
this.style.display = "none";
oSinger.className = "singer rotate";
};

/* 点击实现暂停功能 */
oPause.onclick = function () {
myMusic.pause();
oPlay.style.display = "block";
this.style.display = "none";
oSinger.className = "singer";
};


  • 进度条功能的实现:
a、首先要获取音乐的播放进度,即添加事件、更新时间。

/* 进度条功能 */
var w = oProgress.offsetWidth - oBar.offsetWidth; //计算小滑块可移动的范围
myMusic.addEventListener("timeupdate", function () {
var s = this.currentTime/this.duration; //当前时间/总时间
oBar.style.transform = "translate("+s*w +"px, -0.15rem)"; //滑块随音乐移动
oBg.style.width = s*w + "px";
});

其中:

timeupdate:更新事件

currentTime:当前播放的时间

duration:音乐的总时间


c、拖拽进度条播放音乐/触屏事件拖拽进度条
//触屏事件拖拽进度条
var x = 0, l = 0, _left = 0;
oBar.addEventListener("touchstart", function (e) {
var x = e.changedTouches[0].pageX; //获取手指按下去的位置
document.addEventListener("touchmove", move);
document.addEventListener("touchend", function () { //触屏结束后需要解绑触屏事件
l = _left;
});
});

function move(e) {
var x1 = e.changedTouches[0].pageX;
var _left = x1 -x + l;
if (_left < 0) {
_left = 0;
} else if (_left > w) {
_left = w;
}
oBar.style.transform = "translate("+_left+"px, -0.15rem)";
oBg.style.width = _left + "px";
myMusic.currentTime = _left/w*myMusic.duration;
}


其中,
touchstart:触屏开始事件

touchend:触屏结束事件

changedTouches:触发事件的手指列表数

触发事件结束需要解绑事件(touchend)

硬件加速:是投影,没有重新渲染dome



关于歌曲列表技巧:使用数组来保存歌曲,通过改变音乐的路径来实现换曲功能。


自动换曲功能:
可以使用audio属性的ended事件(媒体已播放到末尾,播放停止)来实现自动换曲功能。
//自动播放下一曲
myMusic.addEventListener("ended", function (e){
n ++;
if (n > 4) {
myMusic.pause();
myMusic.src = "";
oSinger.className = "singer";
oBg.style.width = 0;
oBar.style.transform = "translate("+0+"px, -0.15rem)";
oPlay.style.display = "block";
oPause.style.display = "none";
}
myMusic.src = "mp3/" +musicList[n];
myMusic.play();
});


在页面中显示当前播放的歌曲名:
//用于显示当前播放的歌曲名
myMusic.addEventListener("canplay", function () {
oMusicTitle.innerHTML = musicList[n];
});

canplay事件:指可以播放。也就是在歌曲播放过程的事件。


JS部分全部代码:
window.onload = function () {
var myMusic = document.getElementById("myMusic");
var oPlay = document.getElementsByClassName("play")[0];
var oPause = document.getElementsByClassName("pause")[0];
var oProgress = document.getElementsByClassName("progress")[0];
var oBar = document.getElementsByClassName("bar")[0];
var oBg = document.getElementsByClassName("bg")[0];
var oSinger = document.getElementsByClassName("singer")[0];
var oPrve = document.getElementsByClassName("prev")[0];
var oNext = document.getElementsByClassName("next")[0];
var oMusicTitle = document.getElementsByClassName("musicTitle")[0];


/* 点击实现播放功能 */
oPlay.onclick = function () {
myMusic.play();
oPause.style.display = "block";
this.style.display = "none";
oSinger.className = "singer rotate";
};

/* 点击实现暂停功能 */
oPause.onclick = function () {
myMusic.pause();
oPlay.style.display = "block";
this.style.display = "none";
oSinger.className = "singer";
};

/* 进度条功能 */
var w = oProgress.offsetWidth - oBar.offsetWidth; //计算小滑块可移动的范围
myMusic.addEventListener("timeupdate", function () {
var s = this.currentTime/this.duration; //当前时间/总时间
oBar.style.transform = "translate("+s*w +"px, -0.15rem)"; //滑块随音乐移动
oBg.style.width = s*w + "px";
});



//触屏事件拖拽进度条
var x = 0, l = 0, _left = 0;
oBar.addEventListener("touchstart", function (e) {
var x = e.changedTouches[0].pageX; //获取手指按下去的位置
document.addEventListener("touchmove", move);
document.addEventListener("touchend", function () {
l = _left;
});
});

function move(e) {
var x1 = e.changedTouches[0].pageX;
var _left = x1 -x + l;
if (_left < 0) {
_left = 0;
} else if (_left > w) {
_left = w;
}
oBar.style.transform = "translate("+_left+"px, -0.15rem)";
oBg.style.width = _left + "px";
myMusic.currentTime = _left/w*myMusic.duration;
}


//用数组保存音乐
var musicList = ["儿童歌曲-捉泥鳅.mp3", "李茂山-迟来的爱.mp3", "宋祖英-好日子.mp3",
"谭嘉仪-小幸运.mp3", "王菲-爱不可及.mp3"];
var n = 0; //索引

//页面加载完成后显示的歌曲
oMusicTitle.innerHTML = musicList[n];
myMusic.src = "mp3/"+ musicList[n];

if (myMusic.currentTime > myMusic.duration) {
n ++;
myMusic.src = "mp3/"+ musicList[n];
myMusic.play();
}

//上一曲功能
oPrve.onclick = function () {
n --;
if (n < 0) {
n = 4;
}
myMusic.src = "mp3/"+ musicList[n];
myMusic.play();
oSinger.className = "singer rotate";
oPause.style.display = "block";
oPlay.style.display = "none";
};

//下一曲功能
oNext.onclick = function () {
n++;
if (n > 4) {
n = 0;
}
myMusic.src = "mp3/" +musicList[n];
myMusic.play();
oSinger.className = "singer rotate";
oPause.style.display = "block";
oPlay.style.display = "none";
};

//自动播放下一曲
myMusic.addEventListener("ended", function (e){
n ++;
if (n > 4) {
myMusic.pause();
myMusic.src = "";
oSinger.className = "singer";
oBg.style.width = 0;
oBar.style.transform = "translate("+0+"px, -0.15rem)";
oPlay.style.display = "block";
oPause.style.display = "none";
}
myMusic.src = "mp3/" +musicList[n];
myMusic.play();
});

//用于显示当前播放的歌曲名
myMusic.addEventListener("canplay", function () {
oMusicTitle.innerHTML = musicList[n];
});
};


这里使用"window.onload"事件是为了当加载完成后,播放器显示歌曲列表的第一首歌曲。这样无需在HTML中添加歌曲了。