RT實(shí)現(xiàn)一個(gè)可以在線播放的移動(dòng)端網(wǎng)易云音樂(lè)立磁。
tips:網(wǎng)易云音樂(lè)沒(méi)用響應(yīng)式呈队,因?yàn)樗隽藘商拙W(wǎng)站。用戶使用的PC端時(shí)唱歧,域名為
http://music.163.com/
宪摧;使用移動(dòng)端時(shí),域名為http://music.163.com/m/
颅崩。
PC端和手機(jī)端的區(qū)別
- 屏幕不一樣大
PC端投放廣告的數(shù)量,有很多選擇沿后,主要用來(lái)放廣告沿彭。
手機(jī)端界面小,不能亂放廣告尖滚,放太多廣告影響用戶體驗(yàn)喉刘,點(diǎn)不到內(nèi)容。 - 觸屏
手機(jī)端可以觸屏漆弄。
補(bǔ)充:現(xiàn)在PC端也有可以觸屏的睦裳,如微軟surface pro5。 - 沒(méi)有IE
手機(jī)端沒(méi)有IE撼唾,可以兼容css3廉邑。 - 手機(jī)端省掉一些標(biāo)簽
比如沒(méi)有hover。
開始
- 創(chuàng)建文件夾
mkdir music-demo
- 變?yōu)間it倉(cāng)庫(kù)
git init
//生成.git目錄
- 初始化一下倉(cāng)庫(kù)
npm init //回車到結(jié)束
//生成package.json文件
- 上傳到本地庫(kù)
git add .
git commit -v ==> init
- git文章
Git學(xué)習(xí)
編寫網(wǎng)頁(yè)
- 創(chuàng)建頁(yè)面
touch home.html playlist.html song.html
// 創(chuàng)建首頁(yè) 歌單頁(yè)面 播放頁(yè)面
- 上傳到本地倉(cāng)庫(kù)
git add .
git commit -v ==> add pages
commit查看記錄
git log
git show [commit字符串] //查看修改代碼
- 使用jQuery
npm i jquery --save
//安裝到node_modules文件中
使用ll node-modules/ 可以查看里面的文件
包有jquery券坞,就對(duì)了
- 上傳到本地庫(kù)
git add .
git commit -v ==> install jquery
git status
- 測(cè)試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>網(wǎng)易云音樂(lè)</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 //模擬線上預(yù)覽
(如果沒(méi)有http-server 請(qǐng)安裝 npm install http-server -g)
http://localhost:8080/home.html //訪問(wèn)網(wǎng)頁(yè)
- http-server安裝與介紹
http-server 超輕量級(jí)web服務(wù)器 - 上傳到本地庫(kù)
git add .
git commit -v ==> init home.html
git status
補(bǔ)充:真正做開發(fā)時(shí)
- 使用npm
- 使用git
- 使用http協(xié)議預(yù)覽頁(yè)面
- 用gitignore 把node_modules 排除
- 簡(jiǎn)化項(xiàng)目多余代碼
vi .gitignore ==> /node_modules
//把node_modules根目錄隱藏鬓催,不上傳到git倉(cāng)庫(kù)里
//因?yàn)閚ode_modules要安裝很多需要的庫(kù),一個(gè)項(xiàng)目下來(lái)會(huì)特別大
- 上傳到本地庫(kù)(別嫌麻煩恨锚,做好備份)
git status
git add .gitignore
git commit -v ==> add ignore
git status
- 上傳到GitHub
在GitHub新建空項(xiàng)目
...or push an existing repository from the command line
代碼抄寫到git中
//上傳
- 配置在線GitHub預(yù)覽地址
- Settings ↓↓↓
- GitHub Pages ↓↓↓
- Source ↓↓↓
- master branch ---save
- 預(yù)覽
預(yù)覽頁(yè)面會(huì)提示沒(méi)有jQuery
做到這一步的時(shí)候宇驾,因?yàn)槲野裯ode_modules上傳到GitHub了。猴伶。
刪除了GitHub和本地的node_modules课舍。
所以需要重新安裝一次jQuery
npm i
ll node_modules //檢查是否成功
git add node_modules/jquery/dist/jquery.min.js
會(huì)提示:
// 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.
意思是:這個(gè)路徑被你的gitignore給忽略了塌西。如果你真的想添加他,使用 -f
ok,everybody...
git add node_modules/jquery/dist/jquery.min.js -f
git commit -v //add jquery
- 編寫首頁(yè)
html - 編寫首頁(yè)CSS
使用動(dòng)態(tài)REM
<script>
document.write(`
<style>
html{
font-size: ${document.documentElement.clienWidth/10}px;
}
</style>
`)
</script>
我的博客:動(dòng)態(tài)REM是什么筝尾,如何使用
-
代碼過(guò)程中遇到的問(wèn)題
- inline-block BUG: SVG在div中捡需,底部有點(diǎn)空白,給svg加
vertical-align: top;
可以解決空隙筹淫。 - 邊框?qū)挾?.5px:
width: 200%; height: 200%;transform: scale(.5);
- 內(nèi)容自動(dòng)收縮
方法一:li中加div站辉,給div設(shè)置display:inline-block;vertical-align: top;
方法二(推薦):給li設(shè)置display: flex; justify-content: center; align-items: center;
- 文本多行省略
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
文章:CSS實(shí)現(xiàn)單行损姜、多行文本溢出顯示省略號(hào) - display:flex: 設(shè)置flex里面的div饰剥,不會(huì)出現(xiàn)邊距合并。
- calc()實(shí)現(xiàn)33.3333%布局
calc-CSS| MDN
- GitHub上的node_modules中的JQ沒(méi)有響應(yīng)汰蓉。
cp node_modules/jquery/dist/jquery.min.js ./ //把jquery移動(dòng)到當(dāng)前目錄下
mkdir vendors //創(chuàng)建文件夾
mv jquery.min.js vendors/ //把jQuery 移動(dòng)到文件下
git add .
git status
git commit -v ==> move jquery
git push
//上傳
- 背景圖自動(dòng)填滿 background-size: cover;
background-size- CSS | MDN 文章
- 邊距合并:
方法一(不推薦):overflow:hidden。觸發(fā)BFC棒卷,解決邊距合并顾孽。
方法二:使用偽類,::before ==> content:""; display:table比规。
方法二升級(jí)版:添加公共:
.no-collapse::before{ content: ""; display: table; }
.no-collapse::after{ content: ""; display: table; }
- inline-block BUG: SVG在div中捡需,底部有點(diǎn)空白,給svg加
-
七牛云(存儲(chǔ)數(shù)據(jù)若厚,生成在線URL)
把歌曲和圖片等下載到本地,上傳到七牛云生成在線URL苞俘。- 存儲(chǔ)文件
管理控制臺(tái) --> 對(duì)象存儲(chǔ) --> 內(nèi)容管理 --> 上傳文件 --> 復(fù)制外鏈
- 存儲(chǔ)文件
-
leanClound實(shí)現(xiàn)在線獲取數(shù)據(jù)
leanClound網(wǎng)站創(chuàng)建應(yīng)用 ==> 創(chuàng)建class(設(shè)置限制寫入) ==> 創(chuàng)建Playlist和Song
寫入數(shù)據(jù)時(shí)盹沈,可以界面寫入,也可以使用代碼吃谣。使用代碼 ==> 查看文檔乞封。
幫助 --> 文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·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 // 驗(yàn)證文件是否存在
<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
});
-
驗(yàn)證
ping {{v2Domain}}
然后在項(xiàng)目中編寫如下測(cè)試代碼:var TestObject = AV.Object.extend('TestObject'); // 選擇表名 var testObject = new TestObject(); // 生成一條數(shù)據(jù) testObject.save({ words: 'Hello World!' //數(shù)據(jù)里面的內(nèi)容 }).then(function(object) { alert('LeanCloud Rocks!'); })
運(yùn)行網(wǎng)頁(yè),如果成功岗憋,彈出"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('保存成功'); })
運(yùn)行網(wǎng)頁(yè),如果成功仔戈,彈出"保存成功"关串。
-
批量上傳
看文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·JavaScript --> 對(duì)象 --> 批量操作 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)
-
查詢數(shù)據(jù)
看文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·JavaScript --> 查詢 創(chuàng)建查詢實(shí)例--> var query = new AV.Query('Todo'); query.find().then(function (results) { console.log(results) //測(cè)試能否查詢到 }, function (error) { }); 在console.log輸出所有歌曲信息,則查詢成功-->
-
使用數(shù)據(jù)
最新音樂(lè)部分使用數(shù)據(jù)獲取 let $newList = $('ol#newList') // 創(chuàng)建查詢 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) { });
-
添加加載動(dòng)畫
僅CSS實(shí)現(xiàn)的加載動(dòng)畫 – 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"> 選擇一個(gè)喜歡的樣式 .ball-grid-pulse > div { //假設(shè)加載動(dòng)畫為ball-grid-pulse background: orange; // 添加顏色 } $('#songs-loading').remove() //獲取到數(shù)據(jù)后移除
-
條件查詢
文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·JavaScript --> 查詢 --> SQL查詢 var cql = 'select * from Todo where [列名] = [查詢值]'; AV.Query.doCloudQuery(cql).then(function (data) { // results 即為查詢結(jié)果监徘,它是一個(gè) AV.Object 數(shù)組 var results = data.results; }, function (error) { });
-
搜索頁(yè)面
文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·JavaScript --> 查詢 --> 字符串查詢 $('input#search').on('input',function(e){ let $input = $(e.currentTarget) // 當(dāng)前點(diǎn)擊的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') //顯示搜索結(jié)果的div $('input#search').on('input',function(e){ let $input = $(e.currentTarget) let value = $input.val().trim() //trim()去掉字符串前后的空格 if(value ==""){return $searchResult.empty()} //空的清除顯示結(jié)果 使用or組合查詢晋修,搜索歌手和歌曲名包含字符串的數(shù)據(jù) 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('沒(méi)有結(jié)果') }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) } } }) })
-
搜索使用函數(shù)節(jié)流-解決請(qǐng)求過(guò)多
異步的特點(diǎn)凰盔,發(fā)出去的請(qǐng)求墓卦,不一定按順序相應(yīng)。所以輸入時(shí)給一個(gè)等待時(shí)間户敬,等全部打完之后落剪,再進(jìn)行搜索睁本。比如設(shè)置300毫秒,在300毫秒內(nèi)輸入忠怖,就不進(jìn)行搜索呢堰,等到有300毫秒的停頓,就進(jìn)行搜索凡泣。設(shè)置鬧鐘 var timer = null; <--- 當(dāng)在input輸入的時(shí)候 if(timer){ //如果有定時(shí)器枉疼,清除定時(shí)器 window.clearTimeout(timer) } //沒(méi)有定時(shí)器,設(shè)置一個(gè)定時(shí)器鞋拟,300毫秒執(zhí)行 timer = setTimeout(function(){ console.log('結(jié)束輸入') //測(cè)試使用往衷,可注釋 // 在這輸入以上搜索代碼 timer = null },300) //一般數(shù)值在300~500毫秒
-
-
播放頁(yè)面
-
轉(zhuǎn)動(dòng)的光盤
使用關(guān)鍵幀 @keyframes spin{ 0%{ transform: rotate(0deg) } 100%{ transform: rotate(360deg) } } section.disk > .circle.playing{ animation: spin 10s linear infinite; // 線性 循環(huán) } section.disk > .circle.playing.pause{ animation-play-state:paused; 暫停動(dòng)畫 }
W3C:動(dòng)畫 CSS3 animation 屬性
W3C:轉(zhuǎn)動(dòng) CSS3 transform 屬性
CSS3 動(dòng)畫暫停 animation-play-state 屬性 -
垂直居中專輯
//知道了寬高 160px position: absolute; top: 50%; left: 50%; margin-top: -80px; margin-left: -80px;
-
虛化圖片,并變暗
filter: blur(100px) brightness(.2);
-
querystring 獲取當(dāng)前url的id值
搜索 querystring
JS獲取URL中參數(shù)值(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都需要初始化严卖,所以把初始化新建個(gè)js,用的時(shí)候就引用
mkdir scripts touch av.js each ===> var APP_ID = '6VgSKgCVd6rGXk9NI4hqQfO0-gzGzoHsz'; var APP_KEY = 'Bs6J1KXLot6ifnFwYqePHdDo'; AV.init({ appId: APP_ID, appKey: APP_KEY });
-
通過(guò)id獲取歌曲信息
文檔 --> 數(shù)據(jù)存儲(chǔ)開發(fā)指南·JavaScript --> 對(duì)象 --> 獲取對(duì)象 --> 獲取objectId var query = new AV.Query('Song'); query.get(id).then(function (song) { console.log(song) }
拷貝歌詞,上傳到leancloud
-
通過(guò)正則獲取當(dāng)前歌詞
query.get(id).then(function (song) { // 選擇表明布轿,并搜索id let {url,lyric} = song.attributes // 獲取歌曲url和歌詞 // ES6語(yǔ)法哮笆,等同 let url = song.attributes.url let video = document.createElement('video') //創(chuàng)建video video.src = url; // 歌曲url video.play() // 播放歌曲 let array = [] var parts = lyric.split('\n') //把歌詞字符串分割成字符串?dāng)?shù)組 parts.forEach(function(string,index){ //遍歷數(shù)組 let xxx = string.split(']') //以]分割成字符串?dāng)?shù)組 xxx[0] = xxx[0].substring(1) //刪除第一個(gè)字符"[" // xxx[0] 是歌詞 ; xxx[1] 是索引 //把時(shí)間轉(zhuǎn)換成秒 let regex = /(\d+):([\d.]+)/ //正則獲取時(shí)間 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){ //沒(méi)有最后一項(xiàng) console.log(array[i].lyric) }else if(array[i].time <= current && array[i+1].time > current){ console.log(array[i].lyric) break; } } },500) })
-
把歌詞添加到頁(yè)面上
<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')) })
-
頁(yè)面播放原理
<audio src="http://oxklvemx3.bkt.clouddn.com/xxx.mp3" controls></audio> // controls 會(huì)在瀏覽器顯示控件 --- 使用js向頁(yè)面添加一個(gè)audio 并且把播放地址賦給url let audio = document.createElement('audio') audio.src = "http://oxklvemx3.bkt.clouddn.com/xxx.mp3" audio.play() //播放
-
實(shí)現(xiàn)歌詞滾動(dòng)
setInterval(function(){ let seconds = video.currentTime // 獲取音樂(lè)播放秒數(shù) let $lines = $('.lines > p') // 獲取所有歌詞標(biāo)簽 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 // 當(dāng)前播放歌詞距離頂部距離 -歌詞容器距離頂部距離 - 一行歌詞距離 $('.lines').css(`transform`,`translateY(-${delta}px)`) } },500)
-