RT实现一个可以在线播放的移动端网易云音乐。
根据用户设备自动跳转相匹配页面,不是响应式tips:网易云音乐没用响应式,因为它做了两套网站。用户使用的PC端时,域名为
http://music.163.com/
;使用移动端时,域名为http://music.163.com/m/
。
PC端和手机端的区别
- 屏幕不一样大
PC端投放广告的数量,有很多选择,主要用来放广告。
手机端界面小,不能乱放广告,放太多广告影响用户体验,点不到内容。 - 触屏
手机端可以触屏。
补充:现在PC端也有可以触屏的,如微软surface pro5。 - 没有IE
手机端没有IE,可以兼容css3。 - 手机端省掉一些标签
比如没有hover。
界面
开始
- 创建文件夹
mkdir music-demo
- 变为git仓库
git init
//生成.git目录
- 初始化一下仓库
npm init //回车到结束
//生成package.json文件
- 上传到本地库
git add .
git commit -v ==> init
- git文章
Git学习
编写网页
- 创建页面
touch home.html playlist.html song.html
// 创建首页 歌单页面 播放页面
- 上传到本地仓库
git add .
git commit -v ==> add pages
commit查看记录
git log
git show [commit字符串] //查看修改代码
- 使用jQuery
npm i jquery --save
//安装到node_modules文件中
使用ll node-modules/ 可以查看里面的文件
包有jquery,就对了
- 上传到本地库
git add .
git commit -v ==> install jquery
git status
- 测试jQuery能否能用
vim home.html
==>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>网易云音乐</title>
</head>
<body>
<div id="hi"></div>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script>
$('#hi').text('hello world')
</script>
</body>
</html>
---
:wq
---
http-server -c-1 //模拟线上预览
(如果没有http-server 请安装 npm install http-server -g)
http://localhost:8080/home.html //访问网页
- http-server安装与介绍
http-server 超轻量级web服务器 - 上传到本地库
git add .
git commit -v ==> init home.html
git status
补充:真正做开发时
- 使用npm
- 使用git
- 使用http协议预览页面
- 用gitignore 把node_modules 排除
- 简化项目多余代码
vi .gitignore ==> /node_modules
//把node_modules根目录隐藏,不上传到git仓库里
//因为node_modules要安装很多需要的库,一个项目下来会特别大
- 上传到本地库(别嫌麻烦,做好备份)
git status
git add .gitignore
git commit -v ==> add ignore
git status
- 上传到GitHub
在GitHub新建空项目
...or push an existing repository from the command line
代码抄写到git中
//上传
- 配置在线GitHub预览地址
- Settings ↓↓↓
- GitHub Pages ↓↓↓
- Source ↓↓↓
- master branch ---save
- 预览
预览页面会提示没有jQuery
做到这一步的时候,因为我把node_modules上传到GitHub了。。
删除了GitHub和本地的node_modules。
所以需要重新安装一次jQuery
npm i
ll node_modules //检查是否成功
git add node_modules/jquery/dist/jquery.min.js
会提示:
// The following paths are ignored by one of your .gitignore files:
// node_modules/jquery/dist/jquery.min.js
// Use -f if you really want to add them.
意思是:这个路径被你的gitignore给忽略了。如果你真的想添加他,使用 -f
ok,everybody...
git add node_modules/jquery/dist/jquery.min.js -f
git commit -v //add jquery
- 编写首页
html - 编写首页CSS
使用动态REM
<script>
document.write(`
<style>
html{
font-size: ${document.documentElement.clienWidth/10}px;
}
</style>
`)
</script>
-
代码过程中遇到的问题
- inline-block BUG: SVG在div中,底部有点空白,给svg加
vertical-align: top;
可以解决空隙。 - 边框宽度0.5px:
width: 200%; height: 200%;transform: scale(.5);
- 内容自动收缩
方法一:li中加div,给div设置display:inline-block;vertical-align: top;
方法二(推荐):给li设置display: flex; justify-content: center; align-items: center;
- 文本多行省略
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
文章:CSS实现单行、多行文本溢出显示省略号 - display:flex: 设置flex里面的div,不会出现边距合并。
- calc()实现33.3333%布局
calc-CSS| MDN
⅓ - 2px,三排减6px,把6px分在中间两个空隙。 - GitHub上的node_modules中的JQ没有响应。
cp node_modules/jquery/dist/jquery.min.js ./ //把jquery移动到当前目录下
mkdir vendors //创建文件夹
mv jquery.min.js vendors/ //把jQuery 移动到文件下
git add .
git status
git commit -v ==> move jquery
git push
//上传
- 背景图自动填满 background-size: cover;
background-size- CSS | MDN 文章
- 边距合并:
方法一(不推荐):overflow:hidden。触发BFC,解决边距合并。
方法二:使用伪类,::before ==> content:""; display:table。
方法二升级版:添加公共:
.no-collapse::before{ content: ""; display: table; }
.no-collapse::after{ content: ""; display: table; }
- inline-block BUG: SVG在div中,底部有点空白,给svg加
-
七牛云(存储数据,生成在线URL)
把歌曲和图片等下载到本地,上传到七牛云生成在线URL。- 存储文件
管理控制台 --> 对象存储 --> 内容管理 --> 上传文件 --> 复制外链
- 存储文件
-
leanClound实现在线获取数据
leanClound网站-
创建应用 ==> 创建class(设置限制写入) ==> 创建Playlist和Song
写入数据时,可以界面写入,也可以使用代码。 -
使用代码 ==> 查看文档。
帮助 --> 文档 --> 数据存储开发指南·javascript --> SDK安装 -->
$ npm install leancloud-storage --save
安装在 node_modules/leancloud-storage/dist文件下 ll+该路径查看是否成功
cp node_modules/leancloud-storage/dist/av-min.js vendors //拷贝
ll vendors // 验证文件是否存在
<script src="./vendors/av-min.js"></script> 添加到home.html中
-
初始化
var APP_ID = '6VgSKgCVd6rGXk9NI4hqQfO0-gzGzoHsz';
var APP_KEY = 'Bs6J1KXLot6ifnFwYqePHdDo';
AV.init({
appId: APP_ID,
appKey: APP_KEY
});
-
验证
ping {{v2Domain}}
然后在项目中编写如下测试代码:var TestObject = AV.Object.extend('TestObject'); // 选择表名 var testObject = new TestObject(); // 生成一条数据 testObject.save({ words: 'Hello World!' //数据里面的内容 }).then(function(object) { alert('LeanCloud Rocks!'); })
运行网页,如果成功,弹出"LeanCloud Rocks!"。
-
例子:存一首歌
var SongObject = AV.Object.extend('Song'); var songObject = new SongObject(); songObject.save({ name: '像我这样的人', singer: '毛不易', url: 'http://oxklvemx3.bkt.clouddn.com/%E5%83%8F%E6%88%91%E8%BF%99%E6%A0%B7%E7%9A%84%E4%BA%BA.mp3' }).then(function(object) { alert('保存成功'); })
运行网页,如果成功,弹出"保存成功"。
-
批量上传
看文档 --> 数据存储开发指南·JavaScript --> 对象 --> 批量操作 var SongObject = AV.Object.extend('Song'); var songObject = new SongObject(); songObject.set('name','1') songObject.set('singer','1') var songObject2 = new SongObject() songObject2.set('name','2') let songs = [songObject,songObject2] AV.Object.saveAll(songs)
-
查询数据
看文档 --> 数据存储开发指南·JavaScript --> 查询 创建查询实例--> var query = new AV.Query('Todo'); query.find().then(function (results) { console.log(results) //测试能否查询到 }, function (error) { }); 在console.log输出所有歌曲信息,则查询成功-->
-
使用数据
最新音乐部分使用数据获取 let $newList = $('ol#newList') // 创建查询 var query = new AV.Query('Song'); // query.startsWith('contain', 'true'); query.find().then(function (results) { for( var i = 0;i<results.length;i++){ let song = results[i].attributes let li = ` <li> <h3>${song.name} <span>${song.reMark}</span> </h3> <p> <svg class="icon icon-sq"> <use xlink:href="#icon-sq"></use> </svg> ${song.singer} - ${song.album} </p> <a class="play-button" href="#"> <svg class="icon icon-play"> <use xlink:href="#icon-play"></use> </svg> </a> </li> ` $newList.append(li) } }, function (error) { });
-
添加加载动画
仅CSS实现的加载动画 – Loader.cssnpm i --save loaders.css //安装 cp node_modules/loaders.css/loaders.min.css vendors //拷贝 vim home.html --> 添加引用 <link rel="stylesheet" href="./vendors/loaders.min.css"> 选择一个喜欢的样式 .ball-grid-pulse > div { //假设加载动画为ball-grid-pulse background: orange; // 添加颜色 } $('#songs-loading').remove() //获取到数据后移除
-
条件查询
文档 --> 数据存储开发指南·JavaScript --> 查询 --> SQL查询 var cql = 'select * from Todo where [列名] = [查询值]'; AV.Query.doCloudQuery(cql).then(function (data) { // results 即为查询结果,它是一个 AV.Object 数组 var results = data.results; }, function (error) { });
-
-
搜索页面
文档 --> 数据存储开发指南·JavaScript --> 查询 --> 字符串查询 $('input#search').on('input',function(e){ let $input = $(e.currentTarget) // 当前点击的input let value = $input.val() //input的值 var query = new AV.Query('Song'); //选择表名 query.contains('name',value); //查询包含输入值的歌曲名 query.find().then(function(result){ console.log(result) //输出符合条件的信息 }) }) ---------------------------搜索歌曲(替换以上代码) var $searchResult = $('#searchResult') //显示搜索结果的div $('input#search').on('input',function(e){ let $input = $(e.currentTarget) let value = $input.val().trim() //trim()去掉字符串前后的空格 if(value ==""){return $searchResult.empty()} //空的清除显示结果 使用or组合查询,搜索歌手和歌曲名包含字符串的数据 var query1 = new AV.Query('Song'); var query2 = new AV.Query('Song'); query1.contains('name',value); query2.contains('singer',value); var queryAll = AV.Query.or(query1, query2); query.find().then(function(results){ $searchResult.empty() if(results.length === 0){ $searchResult.html('没有结果') }else{ for( var i = 0; i<results.length; i++){ let song = results[i].attributes let li = ` <li data-id="${results[i].id}"> <a href="./song.html?id=results[i].id"> ${song.name} - ${song.singer}</a> //注意a链接格式。 //歌名和歌手在attributes中,id在results中 </li> ` $searchResult.append(li) } } }) })
-
搜索使用函数节流-解决请求过多
异步的特点,发出去的请求,不一定按顺序相应。所以输入时给一个等待时间,等全部打完之后,再进行搜索。比如设置300毫秒,在300毫秒内输入,就不进行搜索,等到有300毫秒的停顿,就进行搜索。设置闹钟 var timer = null; <--- 当在input输入的时候 if(timer){ //如果有定时器,清除定时器 window.clearTimeout(timer) } //没有定时器,设置一个定时器,300毫秒执行 timer = setTimeout(function(){ console.log('结束输入') //测试使用,可注释 // 在这输入以上搜索代码 timer = null },300) //一般数值在300~500毫秒
-
-
播放页面
-
转动的光盘
使用关键帧 @keyframes spin{ 0%{ transform: rotate(0deg) } 100%{ transform: rotate(360deg) } } section.disk > .circle.playing{ animation: spin 10s linear infinite; // 线性 循环 } section.disk > .circle.playing.pause{ animation-play-state:paused; 暂停动画 }
W3C:动画 CSS3 animation 属性
W3C:转动 CSS3 transform 属性
CSS3 动画暂停 animation-play-state 属性 -
垂直居中专辑
//知道了宽高 160px position: absolute; top: 50%; left: 50%; margin-top: -80px; margin-left: -80px;
-
虚化图片,并变暗
filter: blur(100px) brightness(.2);
-
querystring 获取当前url的id值
搜索 querystring
JS获取URL中参数值(QueryString)的4种方法分享function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配 var context = ""; if (r != null) context = r[2]; reg = null; r = null; return context == null || context == "" || context == "undefined" ? "" : context; } var id = GetQueryString("id");
-
每一次使用leancloud都需要初始化,所以把初始化新建个js,用的时候就引用
mkdir scripts touch av.js each ===> var APP_ID = '6VgSKgCVd6rGXk9NI4hqQfO0-gzGzoHsz'; var APP_KEY = 'Bs6J1KXLot6ifnFwYqePHdDo'; AV.init({ appId: APP_ID, appKey: APP_KEY });
-
通过id获取歌曲信息
文档 --> 数据存储开发指南·JavaScript --> 对象 --> 获取对象 --> 获取objectId var query = new AV.Query('Song'); query.get(id).then(function (song) { console.log(song) }
-
拷贝歌词,上传到leancloud
-
通过正则获取当前歌词
query.get(id).then(function (song) { // 选择表明,并搜索id let {url,lyric} = song.attributes // 获取歌曲url和歌词 // ES6语法,等同 let url = song.attributes.url let video = document.createElement('video') //创建video video.src = url; // 歌曲url video.play() // 播放歌曲 let array = [] var parts = lyric.split('\n') //把歌词字符串分割成字符串数组 parts.forEach(function(string,index){ //遍历数组 let xxx = string.split(']') //以]分割成字符串数组 xxx[0] = xxx[0].substring(1) //删除第一个字符"[" // xxx[0] 是歌词 ; xxx[1] 是索引 //把时间转换成秒 let regex = /(\d+):([\d.]+)/ //正则获取时间 let matches = xxx[0].match(regex) let minute = +matches[1] let seconds = +matches[2] array.push({ time: minute*60+seconds, lyric: xxx[1] }) }) // console.log(array) setInterval(function(){ // console.log(video.currentTime) let current = video.currentTime for(let i = 0;i<array.length; i++){ if(i === array.length -1){ //没有最后一项 console.log(array[i].lyric) }else if(array[i].time <= current && array[i+1].time > current){ console.log(array[i].lyric) break; } } },500) })
-
把歌词添加到页面上
<div class="lyric"> <div class="lines"></div> </div> ---------------------------- let $lyric = $('.lyric') array.map(function(object){ let $p = $('<p/>') $p.attr('data-time',object.time).text(object.lyric) $p.appendTo($lyric.children('.lines')) })
-
页面播放原理
<audio src="//oxklvemx3.bkt.clouddn.com/xxx.mp3" controls></audio> // controls 会在浏览器显示控件 --- 使用js向页面添加一个audio 并且把播放地址赋给url let audio = document.createElement('audio') audio.src = "//oxklvemx3.bkt.clouddn.com/xxx.mp3" audio.play() //播放
-
实现歌词滚动
setInterval(function(){ let seconds = video.currentTime // 获取音乐播放秒数 let $lines = $('.lines > p') // 获取所有歌词标签 let $whichLine for( let i = 0;i < $lines.length; i++){ let currentLineTime = $lines.eq(i).attr('data-time') let nextLineTime = $lines.eq(i+1).attr('data-time') // let bug = $lines.eq(i+1).length !== 0 最后一行bug == $lines[i+1] !== undefined if( $lines[i+1] !== undefined && currentLineTime < seconds && nextLineTime > seconds ){ $whichLine = $lines.eq(i) break; } } if($whichLine){ $whichLine.addClass('active').prev().removeClass('active') let top = $whichLine.offset().top let linesTop = $('.lines').offset().top let delta = top - linesTop - $('.lyric').height()/3 // 当前播放歌词距离顶部距离 -歌词容器距离顶部距离 - 一行歌词距离 $('.lines').css(`transform`,`translateY(-${delta}px)`) } },500)
-
网友评论