Web Player Development Code Refining

Keywords: Javascript JSON JQuery Attribute

4. Refining

Our player is basically implemented, but the code reuse is not high, so we want to encapsulate it as a plug-in.

1. The basic running code of the plug-in is as follows:

;(function(undefined){

'use strict';

... ...

})()

 

The above code is the basic plug-in code. The meaning of this code is detailed below.

The previous semicolon can solve the problem that other codes may cause errors when the plug-in is merged with other js.

The structure'(function(){} ()'means that the function in the first parenthesis is executed immediately. In fact, there is another way to execute the function immediately,'(function(){} ()'.Looking at your preferences, I usually like to use the first one.

"Undefined" is passed in as a parameter because older browsers are not supported, direct use can cause errors, and the js framework considers compatibility, so adding a parameter undefined will not affect undefined inside the plug-in even if someone has defined it outside.

Strict Mode Development

Here is a further complement to the code within the function:

'use strict';

This line of code represents a strict pattern, which, as the name implies, allows Javascript to run under stricter conditions, helping us develop more regularly.If a grammar problem is found during grammar detection, the entire block of code becomes invalid and results in a grammar exception.Execution exceptions are thrown if code violates strict mode occurs during runtime.

Define our player plug-in "playMythology"

Let's really start with our plug-in code. For now, the whole code is as follows:

;(function(undefined){
'use strict';
var _global;
function playMythology(opt) {
... ...
}
playMythology.prototype = {};
//Exposing plug-in objects to global objects
_global = (function() {
return this || (0, eval)('this');
}());
if (typeof module !== "undefined" && module.exports) {
module.exports = playMythology;
} else if (typeof define === "function" && define.amd) {
define(function() {
return playMythology;
});
} else {
!('playMythology' in _global) && (_global.playMythology = playMythology);
}
})()

 

Define "_global" and assign a global environment to a _global.

And assign the current top-level object to this variable, code as follows:

_global = (function() {
return this || (0, eval)('this');
}());

 

Look at this code as an immediate execution function, not the first one mentioned above, but the second one: (functiong(){}) structure; first, the function eval() is introduced: eval() calculates a JavaScript string and executes it as script code. If the parameter is an expression, the eval() function will be persistentLine expression, eval() executes a Javascript statement if the parameter is a Javascript statement.Then parse the statement one by one: return this means to return the current object; the comma operator in the first parenthesis evaluates each of its operands (from left to right) and returns the value of the last one, so this (0, eval)('this') is equivalent to Eval ('this'), so why not use Eval ('this') instead of (0, eval)('this')?In strict mode, if no value is specified for this, it is undefined. To prevent the window variable from being assigned undefined in strict mode, use (0, eval)('this') to re-point this to the global environment object.Because (0, eval)('this') executes GetValue on its operand through a comma expression, calculates a value so that the value of this points to a global object; Eval ('this') calculates a reference, a direct call, and the value of this in the method is a reference to obj.

 

Define "playMythology" to indicate the name of our plug-in.Then let's add properties to this function, and add them through prototype, which simply explains that prototype is a property of a function and is the prototype object of a function.Prototype can only be called by a function.

To modularize plug-ins and make our plug-ins a module, we have to make our plug-ins modular as well.This simply determines if there is a loader, and if there is one, we use the loader, if there is no loader.We use top-level domain objects.The following code does this:

if (typeof module !== "undefined" && module.exports) {

module.exports = playMythology;

} else if (typeof define === "function" && define.amd) {

define(function() {

return playMythology;

});

} else {

!('playMythology' in _global) && (_global.playMythology = playMythology);

}

 

 

Introduces the main operators:'=='means equality;'===' means absolute equality;'!='means inequality;'!==' means strict inequality.In JavaScript, unll is not the same as undefined, but null==undefined is true, null===undefined is false, so null!== undefined is true.

"Typeof" denotes the return data type and can be used in two ways: typeof (expression) and the name of a typeof variable. The first is to operate on an expression, and the second is to operate on a variable.The return type is a string and the values include the following:

1.'undefined'--- Undefined variable or value

2.'boolean'--- Variables or values of Boolean type

3.'string'-- - Variables or values of type string

4.'number'-- Variables or values of type number

5.'object'-- -- variable or value of object type, or null (this is a legacy of js history and treats null as object type)

6.'function'-- Variables of type function or value module.exports objects are created by the module system.When we write the module ourselves, we need to write the module interface at the end of the module, declare what the module exposes to the outside world, and module.exports provides a way to expose the interface.This method can return globally shared variables or methods.

Introducing AMD,AMD is one of the well-known specifications, the full name is Asynchronous Module Definition, which is the asynchronous module loading mechanism.From its specification description page, AMD is short and simple, but it fully describes the module's definition, dependencies, reference relationships, and loading mechanism.Interested friends can study carefully, requireJS, NodeJs, Dojo, JQuery are all in use, we can see its value.

 

2. Basic Functions

Introduction of CSS file functions: front-end development is necessary to introduce CSS files, the main function of CSS is to beautify the page layout, I want to develop plug-in skin can be set dynamically, so to dynamically introduce CSS files, defined the introduction of CSS file functions, the specific code is as follows:

//path Representation introduction CSS File Path

function cssinto(path) {

//If CSS File error, throw error exception

if (!path || path.length === 0) {

throw new Error('argument "path" is required !');

}

//Obtain head object

var head = document.getElementsByTagName('head')[0];

//Establish link Label and Insert into head Inside Label

var link = document.createElement('link');

link.href = path;

link.rel = 'stylesheet';

link.type = 'text/css';

head.appendChild(link);

}

 

Time Conversion Function: Main function, talk about audio currentTime timestamp conversion to "minutes: seconds" display format.

//path Representation introduction CSS File Path

//Time Display Conversion

function conversion(value) {

let minute = Math.floor(value / 60)

minute = minute.toString().length === 1 ? ('0' + minute) : minute

let second = Math.round(value % 60)

second = second.toString().length === 1 ? ('0' + second) : second

return minute+":"+second

}

 

Introduce json file function: file value json file path, callback only has to be a callback function, which is called when the file is loaded.

function readTextFile(file, callback) {

var rawFile = new XMLHttpRequest();

rawFile.overrideMimeType("application/json");

rawFile.open("GET", file, true);

rawFile.onreadystatechange = function() {

if (rawFile.readyState === 4 && rawFile.status == "200") {

callback(rawFile.responseText);

}

}

rawFile.send(null);

}

 

getElementsByClass: Since we are not talking about window incoming plug-ins, there are some methods that we cannot use, so we define the following method implementation to find the dom object in html through class.

//Determine if the plug-in exists " getElementsByClass",No, it will be implemented using the following method.

if (!('getElementsByClass' in HTMLElement)) {

//prototype As mentioned earlier, by " prototype"to HTMLElement Add Attribute Method getElementsByClass"

HTMLElement.prototype.getElementsByClass = function(n) {

var el = [],

_el = this.getElementsByTagName('*');

for (var i = 0; i < _el.length; i++) {

if (!!_el[i].className && (typeof _el[i].className == 'string') && _el[i].className.indexOf(n) > -1) {

el[el.length] = _el[i];

}

}

return el;

};

((typeof HTMLDocument !== 'undefined') ? HTMLDocument : Document).prototype.getElementsByClass = HTMLElement.prototype

.getElementsByClass;

}

 

Parameter Merge Function: Object merge, which is mainly used for plug-in default parameter assignment. Use new parameters if set, or default parameters if not set

//Represents the original parameter, n Represents a new parameter, override Indicates whether to overwrite

function extend(o, n, override) {

for (var key in n) {

if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) {

o[key] = n[key];

}

}

return o;

}

 

3. Basic Functions

Parameter initialization with detailed comments.

_initial: function(opt) {

// Default parameters

var def = {

skinID: "default", //Default skin path

domID: "musicbox" //Set Player Container ID

};

//If the function is initialized, merge when parameters are set, and use default parameters when no parameters are set

this.def = extend(def, opt, true);

//Be used for JSON File Storage Data

this.data = {};

//Player initial volume is 0.3

this.sound = 0.3;

this.currentID = 0;

//Establish audion

this.audion = document.createElement("AUDIO");

//Get Player dom object

this.dom = document.getElementById(def.domID);

//Player initial volume

this.audion.volume = this.sound;

//Define timer for progress bar adjustment, song scrolling, etc.

this.timecolick;

//Song Container

this.songBox;

//Player status, 0 for sequential play, 1 for circular play, and 2 for random play.

this.isPlayState = 0;

//Song lists are used to store song data

this.songList;

//Song playback progress bar

this.songProgress;

//Player head on playback progress bar

this.songPlayHead;

//Determine if the song is allowed to scroll, 0 means allowed, 1 means not allowed

this.isSlide = 0;

//Play progress, 0 indicates initial position

this.playprogress = 0;

//Maximum

this.playMax = 0;

//Whether the player is playing, 0 means playing, 1 means pausing

this.isPlaying = 0;

//Song List Scroll Distance

this.scollHeight = 20;

//Initialize the player and start playing

this._GetData();

},

 

Player interface initializes and plays songs

//Set up player interface

var _this = this;//Save the current object to_this

//Initialization CSS file

cssinto("skin/" + this.def.skinID + "/css/music.css");

//read json data

readTextFile("skin/" + this.def.skinID + "/data.json", function(text) {

//Data Read To data

_this.data = JSON.parse(text);

//Put interface HTML Code insertion container, interface initialization

_this.dom.innerHTML = _this.data[0].MusicHtml;

//Set Song List

var htmlinsert = "";

//Past Song Container dom object

_this.songBox = _this.dom.getElementsByClass(_this.data[0].musiclistbox)[0];

//Store song data

_this.songList = _this.data[0].Songlist;

for (var i = 0; i < _this.songList.length; i++) {

htmlinsert += '<li><span>' + _this.songList[i].songname + '</span></li>';

}

_this.songBox.innerHTML = htmlinsert;

//Set Music List Click Events

for (var i = 0; i < _this.songBox.childNodes.length; i++) {

(

function(j) {

_this.songBox.childNodes[j].onclick = function() {

_this._PlaySong(j);

}

})(i)

}

//Once all the data is loaded, start playing the song

_this._PlaySong(0);

 

Pause the playback function.

//Play stop button event _this.dom.getElementsByClass(_this.data[0].playBT)[0].onclick = function(e) {

//Stop playing if it is playing

if (_this.isPlaying == 0) {

this.className = "playbutton";

_this.isPlaying = 1;

_this.audion.pause()

} else //Start playing if you stop playing

{

this.className = "pausebutton";

_this.isPlaying = 0;

_this.audion.play();

}

}

 

 

Song switch function, previous switch, next switch.

//Previous button

_this.dom.getElementsByClass(_this.data[0].preBton)[0].onclick = function(e) {

if (_this.currentID > 0) {

_this.currentID--;

} else {

_this.currentID = _this.songList.length - 1;

}

_this._PlaySong(_this.currentID)

}

//Next Button

_this.dom.getElementsByClass(_this.data[0].nextBton)[0].onclick = function(e) {

if (_this.currentID < _this.songList.length - 1) {

_this.currentID++;

} else {

_this.currentID = 0;

}

_this._PlaySong(_this.currentID)

}

 

Random play function, songs will be played randomly when the button is clicked.

//Random Play Button

var randombtn = _this.dom.getElementsByClass(_this.data[0].randombtn)[0];

randombtn.onclick = function(e) {

if (_this.isPlayState == 1) {

_this.isPlayState = 0;

this.className = _this.data[0].shuffle;

return;

}

if (_this.isPlayState == 2) {

onereplay.className = _this.data[0].replay;

}

_this.isPlayState = 1;

this.className = _this.data[0].shuffleon;

}

 

Single loop function, the song will be played in a single loop when the button is clicked.

//Single Loop Button

var onereplay = _this.dom.getElementsByClass(_this.data[0].onereplay)[0];

onereplay.onclick = function(e) {

if (_this.isPlayState == 2) {

_this.isPlayState = 0;

this.className = _this.data[0].replay;

return;

}

if (_this.isPlayState == 1) {

randombtn.className = _this.data[0].shuffleon;

}

_this.isPlayState = 2;

this.className =  _this.data[0].replay;

 

}

 

Volume adjustment function, drag and drop volume adjustment function.

//Volume adjustment button

var soundHead = _this.dom.getElementsByClass(_this.data[0].soundHead)[0];

var soundBox = _this.dom.getElementsByClass(_this.data[0].soundBox)[0];

var soundCurrentTime = _this.dom.getElementsByClass(_this.data[0].soundCurrentTime)[0];

soundHead.style.left = _this.sound * 100 + 'px';

soundCurrentTime.style.width = _this.sound * 100 + '%';

soundHead.onmousedown = function(e) {

var x = (e || window.event).clientX;

var l = this.offsetLeft;

var max = soundBox.offsetWidth - this.offsetWidth;

document.onmousemove = function(e) {

var thisX = (e || window.event).clientX;

var to = Math.min(max, Math.max(-2, l + (thisX - x)));

if (to < 0) {

to = 0;

}

soundHead.style.left = to + 'px';

//This sentence removes the selected effect

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

_this.audion.volume = to / max;

//document.querySelector('.now')

soundCurrentTime.style.width = to / max * 100 + '%';

}

//Notice here that document To have a good dragging effect

document.onmouseup = function() {

document.onmousemove = null;

};

}

 

Progress bar function.

//Get Progress Bar dom

_this.songProgress = _this.dom.getElementsByClass(_this.data[0].SongProgress)[0];

//Get the playback head on the progress bar

_this.songPlayHead = _this.dom.getElementsByClass(_this.data[0].playHead)[0];

//Click the progress bar to adjust the playback progress

_this.songProgress.onclick = function(e) {

var x = (e || window.event).clientX;

var left = x - this.offsetLeft - _this.songPlayHead.offsetWidth;

var maxwidth = _this.songProgress.offsetWidth;

_this.dom.getElementsByClass(_this.data[0].playHead)[0].style.left = left + 'px';

var currenttime = _this.audion.duration * (left / maxwidth)

var p = left / maxwidth

_this.audion.currentTime = p * _this.audion.duration;

_this.audion.play();

};

//Drag the player head to adjust the play progress

_this.songPlayHead.onmousedown = function(e) {

var x = (e || window.event).clientX;

var l = this.offsetLeft;

var max = _this.songProgress.offsetWidth - this.offsetWidth;

_this.playMax = max;

document.onmousemove = function(e) {

var thisX = (e || window.event).clientX;

var to = Math.min(max, Math.max(-2, l + (thisX - x)));

if (to < 0) {

to = 0;

}

_this.playprogress = to;

_this.isSlide = 1;

_this.songPlayHead.style.left = to + 'px';

_this.dom.getElementsByClass(_this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.duration * (_this

.playprogress / _this.playMax));

//This sentence removes the selected effect

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

// _this.audion.currentTime = to / max;

 

}

//Notice here that document To have a good dragging effect

document.onmouseup = function() {

_this.isSlide = 0;

_this.audion.currentTime = (_this.playprogress / _this.playMax) * _this.audion.duration;

_this.audion.play();

document.onmousemove = null;

};

 

Timing function function

//Timing function

_this.timecolick = setInterval(function() {

if (_this.isSlide == 1) {

return;

}

//Set Progress Bar

var percent = Math.floor(_this.audion.currentTime / _this.audion.duration * 10000) / 100 + "%";

_this.songPlayHead.style.left = percent;

//Set the current play time

_this.dom.getElementsByClass(_this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.currentTime);

if (_this.audion.ended) {

if (_this.isPlayState == 0) //Sequential Playback

{

if (_this.currentID < _this.songList.length - 1) {

_this.currentID++;

} else {

_this.currentID = 0;

}

} else if (_this.isPlayState == 1) //Random Play

{

_this.currentID = Math.floor(Math.random() * _this.songList.length - 1)

} else //Single tune circulation

{

_this.currentID = _this.currentID;

}

console.log(_this.currentID)

_this._PlaySong(_this.currentID);

}

}, 100)

 

Song playback function

__PlaySong: function(songID) {

var _this = this;

this.audion.setAttribute("src", this.data[0].Songlist[songID].songurl);

this.dom.getElementsByClass(this.data[0].SongName)[0].innerHTML = _this.data[0].Songlist[songID].songname;

_this.dom.getElementsByClass(this.data[0].Singer)[0].innerHTML = this.data[0].Songlist[songID].songer;

_this.audion.onloadedmetadata = function() {

_this.dom.getElementsByClass(this.data[0].SingerCurrentTime)[0].innerHTML = conversion(_this.audion.currentTime);

_this.dom.getElementsByClass(this.data[0].showalltime)[0].innerHTML = conversion(_this.audion.duration)

}

this.audion.play();

var Songlist = _this.songBox.childNodes;

for (var i = 0; i < Songlist.length; i++) {

if (songID == i) {

Songlist.item(i).setAttribute("class", this.data[0].currentSong);

} else {

Songlist.item(i).setAttribute("class", "")

}

}

//console.log(_this.scollHeight*songID)

_this._scollToMusiclist(songID, _this.dom.getElementsByClass(this.data[0].MusicList)[0])

 

}

 

Song scrolling function.

_scollToMusiclist: function(singID, wmusicbox) {

//ok  2019 On April 5, 2000, finally the debugging was successful. It is really not possible to keep the development going for a long time. Many things were unexpected. The reason why I just kept scrolling was that I didn't judge the maximum value. If it exceeds the maximum value, we need to assign the maximum value to the variable, so it won't keep blinking.

var gundong = singID * 20;

var maxgundong = wmusicbox.scrollHeight - wmusicbox.offsetHeight;

if (gundong > maxgundong) {

gundong = maxgundong;

}

var scollTime = setInterval(function() {

console.log(wmusicbox.scrollTop)

if (wmusicbox.scrollTop < gundong) {

wmusicbox.scrollTop = wmusicbox.scrollTop + 1;

console.log(gundong)

} else if (wmusicbox.scrollTop > gundong) {

wmusicbox.scrollTop = wmusicbox.scrollTop - 1;

console.log("2")

} else {

console.log("=")

clearInterval(scollTime);

}

})

}

 

ok, we have finished writing all our web players. I will package the source code and provide you with downloads and valuable comments.Single click download

Posted by dickd on Tue, 07 May 2019 02:20:39 -0700