创建简单的js原生组件之————创建一个好看的html5播放器

更新时间:2016-07-04 16:18:09 点击次数:2144次

一、介绍

由于工作需求,原生的html5播放器虽然好用,但是ui不是太好看(个人觉得还可以)但是过不了设计的眼光,所以需要创建一个好看的播放器组件。一个组件的好处用面向对象的方式来讲就相当于一个类,你可以重复的去新建这个类,生成重复的组件对象。在这里,相当于你可以在同一个页面用new的方式,方便的创建多个自定义的播放器。

html5播放器原理:其实无非还是使用了html5的audio元素,然后基于audio的api自己去写播放器各个方法(播放、暂停、进度条、声音控制)等等,我看了下网易的云音乐的播放器,也是采用的audio的API来控制的。

原生audio控件:

网易云音乐皮肤:

笔者的audio皮肤(虽然挺一般的,但是跟公司的网站色系比较统一)

二、创建简单js组件原理

首先一个js插件关键的要点就是 不依赖、不污染、独立,不依赖与其它的方法和元素,独立自成一体。
多基于jquery的插件会依赖于jquery,我也写过一些jquery的插件,但是这次要写的是完全基于原生js的插件。

使用IIFE架构

IIFE:immediately invoked functional expression 就是我们平常所说的立即执行函数:

(function() {

}());

然后我们需要一个构造函数来实现一个类,关于如何用js实现类可以参考一些js的书籍,这里我们使用构造函数的方式。在立即执行函数中的作用域是全局 window, 函数中的this 就代表的是 window ,如下先定义this.AudioPlayer 就等于window.AudioPlayer , 这样相当于AudioPlayer这个变量名称已经在全局作用域中使用了。

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

}
}());

然后建立一个对象就简单了,直接 var _audioPlayer = new AudioPlayer()就创建了一个对象。

传入参数

一般来讲,一个对象总会有一些初始化参数,比如我们的播放器AudioPlayer就可以有 音乐的url参数,是否需要音量控制的参数等等。 我们在构造函数的内部需要创建一个缺省的参数对象defaults,然后还需要有一个传入的参数和缺省的参数相互匹配的一个方法。

(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组件的框架就搭建起来了,在里面不断的加入方法和功能就可以了。

三、编写一个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> 

结果如下:

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!