建立簡單的js原生組件之————建立一個好看的html5播放器

1、介紹

因爲工做需求,原生的html5播放器雖然好用,可是ui不是太好看(我的以爲還能夠)可是過不了設計的眼光,因此須要建立一個好看的播放器組件。一個組件的好處用面向對象的方式來說就至關於一個類,你能夠重複的去新建這個類,生成重複的組件對象。在這裏,至關於你能夠在同一個頁面用new的方式,方便的建立多個自定義的播放器。javascript

html5播放器原理:其實無非仍是使用了html5的audio元素,而後基於audio的api本身去寫播放器各個方法(播放、暫停、進度條、聲音控制)等等,我看了下網易的雲音樂的播放器,也是採用的audio的API來控制的。css

原生audio控件:
圖片描述html

網易雲音樂皮膚:
圖片描述html5

筆者的audio皮膚(雖然挺通常的,可是跟公司的網站色系比較統一)
圖片描述java

2、建立簡單js組件原理

首先一個js插件關鍵的要點就是 不依賴、不污染、獨立,不依賴與其它的方法和元素,獨立自成一體。
最多基於jquery的插件會依賴於jquery,我也寫過一些jquery的插件,可是此次要寫的是徹底基於原生js的插件。jquery

使用IIFE架構

IIFE:immediately invoked functional expression 就是咱們日常所說的當即執行函數:ios

(function() {

}());

而後咱們須要一個構造函數來實現一個類,關於如何用js實現類能夠參考一些js的書籍,這裏咱們使用構造函數的方式。在當即執行函數中的做用域是全局 window, 函數中的this 就表明的是 window ,以下先定義this.AudioPlayer 就等於window.AudioPlayer , 這樣至關於AudioPlayer這個變量名稱已經在全局做用域中使用了。git

(function() {

this.AudioPlayer = function AudioPlayer() {

}
}());

而後創建一個對象就簡單了,直接 var _audioPlayer = new AudioPlayer()就建立了一個對象。github

傳入參數

通常來說,一個對象總會有一些初始化參數,好比咱們的播放器AudioPlayer就能夠有 音樂的url參數,是否須要音量控制的參數等等。 咱們在構造函數的內部須要建立一個缺省的參數對象defaults,而後還須要有一個傳入的參數和缺省的參數相互匹配的一個方法。express

(function(){
    this.AudioPlayer = function AudioPlayer() {
        var config;
        
        //定義缺省參數
        var defaults = {
            audiodom:'',
            audiosrc:'',
            showVolume:true
        }

        //傳入的參數於缺省參數的對應
        if (arguments[0] && typeof arguments[0] === "object") {
            config = extendDefaults(defaults, arguments[0]);
        }
    }
        
    
    function extendDefaults(source, properties) {
        var property;
        for(property in properties) {
            if (properties.hasOwnProperty(property)) {
                source[property] = properties[property];
            }
        }
        return source;
    }
})();

使用prototype建立公有方法

公有方法的做用很明顯,能夠建立這個對象的一些在外部須要調用的功能,如: 我在這裏簡單的寫了一個當播放器切換音樂來源url的時候的一個公有方法,由於當須要換音樂url的時候,不須要再去從新建立一個播放器對象了。

AudioPlayer.prototype.setAudioSrc = function (src) {
        this.audioPlayer.setAttribute('src',src);
    }

整合在一塊兒寫就是這樣:

(function(){
    this.AudioPlayer = function AudioPlayer() {
        var config;
        
        //定義缺省參數
        var defaults = {
            audiodom:'',
            audiosrc:'',
            showVolume:true
        }

        //傳入的參數於缺省參數的對應
        if (arguments[0] && typeof arguments[0] === "object") {
            config = extendDefaults(defaults, arguments[0]);
        }
    }
       
    //公有方法
    AudioPlayer.prototype.setAudioSrc = function (src) {
        this.audioPlayer.setAttribute('src',src);
    } 
    
    function extendDefaults(source, properties) {
        var property;
        for(property in properties) {
            if (properties.hasOwnProperty(property)) {
                source[property] = properties[property];
            }
        }
        return source;
    }
})();

總結:這樣基本上寫一個簡單js組件的框架就搭建起來了,在裏面不斷的加入方法和功能就能夠了。

3、編寫一個html5播放器

如下就是一個播放器的js代碼,css部分我就不貼出代碼來了,附上github 的地址:

https://github.com/tangolivesky/audioplayer

(function () {
    this.AudioPlayer = function AudioPlayer() {

        var config;

        // Define option defaults
        var defaults = {
            audiodom:'',
            audiosrc:'',
            showVolume:true
        }

        // Create options by extending defaults with the passed in arugments
        if (arguments[0] && typeof arguments[0] === "object") {
            config = extendDefaults(defaults, arguments[0]);
        }

        var duration;
        var myAudioPlayer = document.createElement("div");
        var audioPlayer = document.createElement("audio");
        var playButton = document.createElement("button");
        var timeLine = document.createElement("div");
        var timeProgressBar = document.createElement("span");
        var playhead = document.createElement("div");
        var currentTime = document.createElement("div");
        var volumeLine = document.createElement("div");
        var volumeLineBar = document.createElement("span");
        var volumeLineHead = document.createElement("div");
        var volumeHorn = document.createElement('span');
        var playheadSpan = document.createElement('span');

        var timelineWidth = 230;
        var volumelinewidth = 50;
        var onplayhead = false;
        var volumeStatus = [];

        this.myAudioPlayer = myAudioPlayer;
        this.playhead = playhead;
        this.timeProgressBar = timeProgressBar;
        this.timelineWidth = timelineWidth;
        this.playButton = playButton;
        this.currentTime = currentTime;
        this.transTime = transTime;
        this.intialStatus = intialStatus;
        this.playStatus = playStatus;
        this.volumeHorn = volumeHorn;
        this.audioPlayer = audioPlayer;

        myAudioPlayer.className = "audioplayer";
        playButton.className = "playbutton play";
        timeLine.className = "timeline";
        timeProgressBar.className = "time-progress-bar";
        playhead.className = "playhead intial";
        playheadSpan.className = 'round';
        currentTime.className = "current-time";
        audioPlayer.setAttribute('controls', 'controls');
        audioPlayer.style.display = "none";
        volumeLine.className = "audio-line";
        volumeLineHead.className = "audio-line-head";
        volumeLineBar.className = "audio-line-bar";
        volumeHorn.className = 'horn full';


        if(config.audiodom === ''){
            document.body.appendChild(myAudioPlayer);
        }else{
            document.getElementById(config.audiodom).appendChild(myAudioPlayer);
        }
        myAudioPlayer.appendChild(playButton);
        playhead.appendChild(playheadSpan);
        timeLine.appendChild(timeProgressBar);
        timeLine.appendChild(playhead);
        myAudioPlayer.appendChild(timeLine);
        myAudioPlayer.appendChild(currentTime);
        myAudioPlayer.appendChild(audioPlayer);
        volumeLine.appendChild(volumeLineBar);
        volumeLine.appendChild(volumeLineHead);
        myAudioPlayer.appendChild(volumeHorn);
        myAudioPlayer.appendChild(volumeLine);

        if (config.hasOwnProperty("audiosrc")) {
            audioPlayer.setAttribute('src', config.audiosrc);
        }
        else{
            playButton.setAttribute("disabled", "disabled");
            timeLine.setAttribute("disabled", "disabled");
            volumeLine.setAttribute("disabled", "disabled");
            playhead.setAttribute("disabled", "disabled");
            volumeLineHead.setAttribute("disabled", "disabled");
            volumeHorn.setAttribute("disabled", "disabled");
        }

        if(config.hasOwnProperty("showVolume")){
            if(!config.showVolume){
                volumeLine.style.display='block';
                volumeLineHead.style.display='block';
                volumeLineBar.style.display='block';
                myAudioPlayer.style.width ='430px';
            }
        }

        audioPlayer.addEventListener('loadedmetadata',function(){
            currentTime.innerHTML = transTime(parseInt(audioPlayer.duration));
        },false);
        playButton.addEventListener('click', play, false);
        audioPlayer.addEventListener('timeupdate', timeUpdate, false);
        audioPlayer.addEventListener('canplaythrough', function () {
            duration = audioPlayer.duration;
        }, false);
        timeLine.addEventListener('click', function (event) {
            moveplayhead(event);
            audioPlayer.currentTime = duration * clickPercent(event);
        }, false);
        playhead.addEventListener('mousedown', mouseDown, false);
        window.addEventListener('mouseup', mouseUp, false);
        volumeLine.addEventListener('click', function (event) {
            movevolumehead(event);
            audioPlayer.volume = volumeClickPercent(event);
            if (audioPlayer.volume == 0) {
                volumeHorn.className = 'horn';
            }else if(audioPlayer.volume>=0.8){
                volumeHorn.className = 'horn full';
            }else if(audioPlayer.volume>=0.5){
                volumeHorn.className = 'horn two';
            }else if(audioPlayer.volume>0){
                volumeHorn.className = 'horn one';
            }
        }, false);
        //volumeLineHead.addEventListener('mousedown', volumeMouseDown, false);
        //window.addEventListener('mouseup', volumeMouseUp, false);
        //聲音按鈕控制
        volumeHorn.addEventListener('click',function(event){
            if (audioPlayer.volume > 0) {
                volumeStatus[0] = audioPlayer.volume;
                volumeStatus[1] = volumeHorn.className;
                volumeStatus[2] = volumeLineBar.style.width;
                volumeStatus[3] = volumeLineHead.style.marginLeft;
                volumeHorn.className = 'horn';
                movevolumehead(event);
                audioPlayer.volume = volumeClickPercent(event);
            }else{
                audioPlayer.volume = volumeStatus[0];
                volumeHorn.className = volumeStatus[1];
                volumeLineBar.style.width = volumeStatus[2];
                volumeLineHead.style.marginLeft = volumeStatus[3];
            }
        },false);

        //樣式調整
        //設置成初始狀態
        function intialStatus(){
            playhead.className = 'playhead intial';
        }
        //設置成播放狀態
        function playStatus(){
            playhead.className = 'playhead';
        }
        function mouseDown() {
            //樣式調整
            playStatus();

            onplayhead = true;
            window.addEventListener('mousemove', moveplayhead, true);
            audioPlayer.removeEventListener('timeupdate', timeUpdate, false);
        }

        function mouseUp(e) {
            //樣式調整
            if (parseInt(playhead.style.marginLeft) <= 0) {
                intialStatus();
            }

            if (onplayhead == true) {
                moveplayhead(e);
                window.removeEventListener('mousemove', moveplayhead, true);
                // change current time
                audioPlayer.currentTime = duration * clickPercent(e);
                audioPlayer.addEventListener('timeupdate', timeUpdate, false);
            }
            onplayhead = false;
        }

        function clickPercent(e) {
            var timelineleft = getOffsetLeft(timeLine);
            return (e.pageX - timelineleft) / timelineWidth;
        }

        function volumeClickPercent(e) {
            var volume = 0;
            var volumeLineLeft = getOffsetLeft(volumeLine);
            if ((e.pageX - volumeLineLeft) / volumelinewidth < 0)volume = 0;
            if ((e.pageX - volumeLineLeft) / volumelinewidth > 1)volume = 1;
            if ((e.pageX - volumeLineLeft) / volumelinewidth >= 0 && (e.pageX - volumeLineLeft) / volumelinewidth <= 1)volume = (e.pageX - volumeLineLeft) / volumelinewidth;
            return volume;
        }

        function moveplayhead(e) {
            var timelineleft = getOffsetLeft(timeLine);
            var newMargLeft = e.pageX - timelineleft;
            if (newMargLeft >= 0 && newMargLeft <= timelineWidth) {
                playhead.style.marginLeft = newMargLeft + "px";
                timeProgressBar.style.width = newMargLeft * 100 / timelineWidth + "%";
            }
            if (newMargLeft < 0) {
                playhead.style.marginLeft = "0px";
                timeProgressBar.style.width = "0%";
            }
            if (newMargLeft > timelineWidth) {
                playhead.style.marginLeft = timelineWidth + "px";
                timeProgressBar.style.width = "100%";
            }
        }

        function movevolumehead(e) {
            var volumeLineLeft = getOffsetLeft(volumeLine);
            var newMargLeft = e.pageX - volumeLineLeft;
            if (newMargLeft >= 0 && newMargLeft <= volumelinewidth) {
                volumeLineHead.style.marginLeft = newMargLeft-10 + "px";
                volumeLineBar.style.width = newMargLeft * 100 / volumelinewidth + "%";
            }
            if (newMargLeft < 0) {
                volumeLineHead.style.marginLeft = "-10px";
                volumeLineBar.style.width = "0%";
            }
            if (newMargLeft > timelineWidth) {
                volumeLineHead.style.marginLeft = volumelinewidth-10 + "px";
                volumeLineBar.style.width = "100%";
            }
        }

        function play() {
            //樣式控制
            playStatus();

            // start music
            if (audioPlayer.paused) {
                audioPlayer.play();
                // remove play, add pause
                playButton.className = "";
                playButton.className = "playbutton pause";
            } else { // pause music
                audioPlayer.pause();
                // remove pause, add play
                playButton.className = "";
                playButton.className = "playbutton play";
            }
        }

        function timeUpdate() {
            var playPercent = audioPlayer.currentTime / duration;
            var playPercentWidth = timelineWidth * playPercent;
            var playTime = transTime(parseInt(audioPlayer.currentTime));
            currentTime.innerHTML = playTime;

            playhead.style.marginLeft = playPercentWidth + "px";
            timeProgressBar.style.width = playPercent * 100 + "%";
            if (audioPlayer.currentTime == duration) {
                playButton.className = "";
                playButton.className = "playbutton play";
            }
        }
        function transTime(time){
            if (time<10) {
                return('00:0'+time);
            }else if(time<60){
                return('00:'+time);
            }else if(time<600){
                var i = parseInt(time/60);
                var j = parseInt(time%60);
                if (j<10) {
                    return('0'+i+':0'+j);
                }else{
                    return('0'+i+':'+j);
                }

            }else if(time<6000){
                var i = parseInt(time/60);
                var j = parseInt(time%60);
                if (j<10) {
                    return(i+':0'+j);
                }else{
                    return(i+':'+j);
                }
            }else{
                return time;
            }
        }

        function volumeMouseDown() {
            onplayhead = true;
            window.addEventListener('mousemove', movevolumehead, true);
            //audioPlayer.removeEventListener('timeupdate', timeUpdate, false);
        }

        function volumeMouseUp(e) {
            if (onplayhead == true) {
                movevolumehead(e);
                window.removeEventListener('mousemove', movevolumehead, true);
                audioPlayer.volume = volumeClickPercent(e);
            }
            onplayhead = false;
        }
        function getOffsetLeft( elem )
        {
            var offsetLeft = 0;
            do {
                if ( !isNaN( elem.offsetLeft ) )
                {
                    offsetLeft += elem.offsetLeft;
                }
            } while( elem = elem.offsetParent );
            return offsetLeft;
        }
    }

    AudioPlayer.prototype.getAudioPlayer = function () {
        return this.myAudioPlayer;
    };

    AudioPlayer.prototype.setAudioSrc = function (src) {
        this.audioPlayer.setAttribute('src',src);
    }
    
    // Utility method to extend defaults with user options
    function extendDefaults(source, properties) {
        var property;
        for (property in properties) {
            if (properties.hasOwnProperty(property)) {
                source[property] = properties[property];
            }
        }
        return source;
    }

})();

在html中調用js播放器組件

在html調用就比較簡單了,只須要一點點的代碼,甚至不須要了解audio標籤,就能夠生成兩個互不衝突的音樂播放器。

<div>
    <div id="audio1">
    </div>
    <div id="audio2">
    </div>
</div>

<script type="text/javascript" src="audioplayer.js"></script>

<script type="text/javascript">

    var audioPlayer = new AudioPlayer({
        audiodom:"audio1",
        audiosrc:"http://www.alexkatz.me/codepen/music/interlude.mp3",
    });


    var audioPlayer2 = new AudioPlayer({
        audiodom:"audio2",
        audiosrc:"http://www.alexkatz.me/codepen/music/interlude.mp3",
    });

</script>

結果以下:
圖片描述

相關文章
相關標籤/搜索