vue——一個頁面實現音樂播放器

項目地址:github.com/ermu5922752…css

演示地址:ermu592275254.github.io/MiniMusicPl…(歌曲連接已失效)html

開發前構思

界面

作音樂播放器,界面必定要炫酷。太low了聽歌沒感受。自己是爲了在上班的時候用,因而作成了一個相似網易雲音樂的界面,大小合適。不用兼容手機端。vue

用css作圖標html5

本懷着簡單實用的需求去考慮,圖標可用SVG、url或者css。相對於url,SVG和css更好一些。爲了修煉,最終選擇的css。利用好after和before,能減小不少dom嵌套。node

.next {
    position: relative;
    display: inline-block;
    height: 36px;
    width: 36px;
    border: 2px solid #fff;
    border-radius: 20px;
    -webkit-border-radius: 20px;
    -moz-border-radius: 20px;
}
        
.next:before {
    content: '';
    height: 0;
    width: 0;
    display: block;
    border: 10px transparent solid;
    border-right-width: 0;
    border-left-color: #fff;
    position: absolute;
    top: 8px;
    left: 10px;
}

.next:after {
    content: '';
    height: 20px;
    width: 4px;
    display: block;
    background: #fff;
    position: absolute;
    top: 8px;
    left: 22px;
}

複製代碼

畫一個唱片webpack

網易雲的唱片很好看,我也要弄一個唱片! 用好box-shadow,一個元素即可以作成很好看的唱片效果。css3

.disc {
    position: relative;
    margin-top: 10%;
    margin-left: 10%;
    width: 300px;
    height: 300px;
    border-radius: 300px;
    transform: rotate(45deg);
    background-image: radial-gradient(5em 30em ellipse, #fff, #000);
    border: 2px solid #131313;
    box-shadow: 0 0 0 10px #343935;
    opacity: 0.7;
}
複製代碼

用range作進度條git

audio自己的樣式很難看,而且不一樣的瀏覽器呈現出來的效果也不同。固然你能夠修改audio的樣式,傳統的作法是經過controls屬性來隱藏audio,而後用div來代替。如今是html5時代了,固然要用更符合場景的新元素————range。github

input[type=range] {
    -webkit-appearance: none;
    width: 80%;
    height: 8px;
    border-radius: 10px;
    background-color: #fff;
}
input[type=range]::-webkit-slider-thumb{
    -webkit-appearance: none;
} 
input[type=range]::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: 20px;
}
input[type=range]:focus {
    outline: none;
}

input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    margin-top: -3px;
    height: 14px;
    width: 14px;
    background: #eb7470;
    border-radius: 50%;
    border: solid 3px #fff;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.5);
}
複製代碼

背景濾鏡模糊web

將圖片設置爲背景的感受很棒,能夠說整個播放器的顏值這背景提供了一半。設置也很是簡單,用到了css3的濾鏡。

.bg-blur {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
    filter: blur(20px);
    z-index: -1;
}
複製代碼

背景圖片經過js控制。

<div class="bg-blur" :style="`background-image:url(${currentSong.album_logo})`"></div>
複製代碼

歌曲資源

爬下接口

直接去蝦米官網打開network,將url複製到postman裏面去作請求。經過修改headers發現,會校驗Referer。也就是說只有蝦米容許的域名能夠訪問此接口。 http://api.xiami.com/web?v=2.0&app_key=1&key=aliez&page=1&limit=5&callback=jsonp154&r=search/songs

解決跨域問題

由於接口支持jsonp。起初嘗試將chrome瀏覽器設置跨域,而後經過$.ajax去作一個jsonp的請求。能夠正常訪問。

以後忽然不行了,是否是蝦米作了限制?

遂改用node啓動一個服務,去僞造referer發起請求,再將請求轉發到頁面。無心中寫了一個代理。

...
case '/song':
    let songOptions = {
        url: 'http://api.xiami.com/web?'+ urlArr[1],
        headers: {
            'Referer': 'http://m.xiami.com/'
        }
    };
    function callback1(error, response, body) {
        if (!error && response.statusCode == 200) {
            res.end(body);
        }
    }
    request(songOptions, callback1);
    break;
...
複製代碼

歌詞滾動

做爲一款逼格比較高的播放器,歌詞滾動是必須的。

原理

將每一句歌詞保存爲一個對象,有對應的時間。當歌曲播放的當前時長大於或等於歌詞的時間,小於此歌詞的下一句歌詞的時間,那麼就將此歌詞滾動到可視區域。而且修改字體顏色。

格式化歌詞

接口返回的歌詞一臉懵逼,仔細研究一下,發現是有規律的。

[ti:aLIEz]
[ar:SawanoHiroyuki[nZk]:mizuki]
[al:o1]
[ly:澤野弘之]
[mu:澤野弘之]
[ma:]
[pu:]
[by:ttpod]
[total:268512]
[offset:0]
[00:00.000]<195>aLIEz <199>- <451>SawanoHiroyuki[nZk]:mizuki
[x-trans]徹頭徹尾的謊話 - SawanoHiroyuki[nZk]:mizuki
[00:01.095]<201>做<250>詞<200>:<201>澤<200>野<199>弘<300>之
[x-trans]
[00:02.846]<200>做<150>曲<150>:<200>澤<200>野<351>弘<349>之
[x-trans]
[00:20.828]<200>決<250>め<200>つ<201>け<149>ば<201>か<349>り
[x-trans]一直專斷專權
[00:23.279]<200>自<200>惚<200>れ<200>を<200>着<400>た
[x-trans]老是自負逞強
[00:24.979]<200>チ<200>ー<200>プ<450>な<550>hokori<350>で
[x-trans]明明只是一文不值的驕傲
......
   refactoringLyrics(lyric){
    let text = lyric.split('[offset:0]')[1];
    let textArr = text.split('\n');
    let lyricsArr = [], translate = [];
    textArr.forEach((item, index) => {
        let time = 0, text = '';
        if (item.indexOf('[x-trans]') > -1) {
            translate.push(item.split('[x-trans]')[1])
        } else if (item.trim() != '') {
            time = item.slice(1, 6).split(':');
            time = parseInt(time[0]) * 60 + parseInt(time[1]);
            text = item.slice(11);
            let arr = text.split('>');
            let str = arr.reduce((a, b) => {
                return a.split('<')[0] + b.split('<')[0]
            });
            let obj = {
                time: time,
                text: str
            };
            lyricsArr.push(obj);
        }
    });
    for (let i in translate) {
        lyricsArr[i].text = lyricsArr[i].text + '\n' + translate[i];
    }
    this.currentLyrics = lyricsArr;
},
複製代碼

搜索欄實現

同文件下子組件掛載

爲了遵循模塊化開發,決定將搜索欄寫成一個子組件。在同一頁面下寫子組件,子組件掛載到對應的template就有講究了。此template不能被父組件的掛載元素包含,不然父組件渲染時會由於沒法渲染子組件中的數據而報undefined。

<div id="app" class="main">
...
</div>
<template id="search-box">
...
</template>

var searchBox = {
        template: '#search-box',
        props: {
            isShow: Boolean,
            openFun: Function
        },
        data(){
            return {
                resultList: [],
                searchValue: '',
            }
        },
        methods: {
        }
    };
 new Vue({
    el: '#app',
    components: {
        'com-tip': tip,
        'search-box': searchBox
    },
    ...
})
複製代碼

eventBus解決數據傳輸

經過jsonp去請求數據,須要設置一個callback函數,此callback寫成一個全局函數,若是不這樣寫,而是經過 searchBox.methods.callback的形式,this指向將爲methods。而沒法直接給searchBox的data賦值。 因而經過eventBus來處理,這樣更易維護。

var EventBus = new Vue();
var callBack = function(result) {
    console.log(result);
    EventBus.$emit('callBack', result);
};
...
mounted(){
    let self = this;
    EventBus.$on('callBack', function(res) {
        if (res && res.data) {
            self.resultList = res.data.songs;
        }
    })
}
...
複製代碼

localStrong儲存歌曲信息

下次再打開,應該播放列表應該保留上一次的數據,這個可直接用localstrong實現

技術補充

濾鏡模糊 http://www.zhangxinxu.com/wordpress/2013/11/css-svg-image-blur/

css圖標 www.uiplayground.in/css3-icons/

flex 兼容寫法: www.cnblogs.com/iriszhang/p…

flex 佈局教程 www.ruanyifeng.com/blog/2015/0…

滑動條樣式自定義 blog.csdn.net/u013347241/…

隱藏滾動條兼容 segmentfault.com/q/101000000…

audio屬性 developer.mozilla.org/zh-CN/docs/…

audio事件 developer.mozilla.org/zh-CN/docs/…

踩了坑

prop傳遞數據

使用cdn,vue的prop只支持中線格式,駝峯格式不生效

ps: 在用webpack打包的項目中用駝峯是能夠,在打包過程當中,會作處理。

// 正確寫法
<search-box :is-show="showSearch" :open-fun="openSearch" @push-song="pushNewSong"
                @play-song="playSong"></search-box>
// 錯誤寫法
<search-box :isShow="showSearch" :openFun="openSearch" @pushSong="pushNewSong"
                @playSong="playSong"></search-box>
複製代碼

待優化

手動修改進度,偶爾會不生效。

搜索暫不支持分頁

不支持建歌單

背景顏色與進度條顏色相近需修改進度條顏色

不支持播放模式選擇-單曲循環-隨機播放

相關文章
相關標籤/搜索