关于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中输入对应的代码就相对应按钮,如:输入“”就相当于“上一曲按钮”。
使用这种图标分三个步骤:使用之前需要下载图标文件:阿里矢量图标管网,下载完成后:将里面的文件保存在一个文件夹里面,接着:
- 第一步,使用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";
};
- 进度条功能的实现:
/* 进度条功能 */
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中添加歌曲了。