Points techniques : ES6+Webpack+HTML5 Audio+Sass
Ici, nous allons apprendre étape par étape comment implémenter un lecteur de musique H5 à partir de zéro.
Jetons d'abord un coup d'œil à l'implémentation finale : lien de démonstration
Puis passons aux choses sérieuses :
Pour créer un lecteur de musique dont vous avez besoin Je connais très bien la façon dont l'audio est lu sur le Web. La balise audio HTML5
est généralement utilisée. Concernant la balise audio, elle possède un grand nombre de propriétés, de méthodes et d'événements. .
Attributs :
src : obligatoire, source audio ;
contrôles : commun, le panneau de contrôle audio par défaut du navigateur sera affiché après le réglage et la balise audio sera masquée par défaut si elle n'est pas définie ;
lecture automatique : commune, lire automatiquement l'audio après le réglage (non pris en charge par le terminal mobile) ;
boucle : commune, l'audio sera lu en boucle après le réglage
préchargement : commun, définir le préchargement audio (non pris en charge par le mobile) ; terminal);
volume : rare , définit ou renvoie la taille de l'audio, la valeur est un nombre à virgule flottante entre 0 et 1 (non pris en charge par les terminaux mobiles
muted : rare, définit ou renvoie l'état muet );
duration : rare, renvoie la durée de l'audio ;
currentTime : rare, définit ou renvoie l'heure de lecture actuelle ;
paused : rare, renvoie l'état de lecture actuel, s'il faut mettre en pause ;
buffered : rare ; , un objet TimeRanges contenant des informations de période mises en mémoire tampon, c'est-à-dire la progression du chargement. Cet objet contient un attribut length, qui renvoie un nombre commençant à 0 pour indiquer combien de segments audio sont actuellement mis en mémoire tampon. Il contient également deux méthodes, start et end, qui doivent chacune être transmises dans un paramètre, c'est-à-dire quel segment du fichier ; l’audio a été chargé à partir de 0. start renvoie l'heure de début du segment et end renvoie l'heure de fin du segment. Par exemple : passez 0, le début du premier paragraphe est 0, l'heure de fin est 17, l'unité est en secondes ; l'attribut
est introduit ici, il peut y avoir des attributs moins couramment utilisés tels que : playbackRate, etc. ., pendant la lecture vidéo Il peut être utilisé, mais je ne l'expliquerai pas encore.
Méthodes :
play() : Démarrer la lecture audio ;
pause() : Mettre en pause la lecture audio
Événement :
canplay : L'audio actuel peut commencer à jouer ( seule une partie de la mémoire tampon est chargée, mais tout n'est pas chargé
canplaythrough : peut être lu sans pause (c'est-à-dire que tout l'audio est chargé
durationchange : la durée de l'audio change
terminée ); la lecture se termine ;
erreur : une erreur s'est produite ;
pause : la lecture est en pause ;
lecture : la lecture commence
progression : déclenchée pendant le processus de déclenchement de l'événement, la progression du chargement. peut être obtenu en accédant à l'attribut buffered de l'audio ;
seek : Déclenché pendant le saut audio, c'est-à-dire lorsque currentTime est modifié
seeked : Déclenché lorsque le saut audio est terminé, c'est-à-dire lorsque currentTime est modifié ; 🎜>timeupdate : déclenché pendant la lecture audio et l'attribut currentTime est mis à jour de manière synchrone ;
Les événements sont présentés ici. Il peut y avoir des événements moins couramment utilisés qui ne seront pas encore expliqués.
Enfin, expliquons le flux d'événements déclenchés par un audio du début du chargement à la fin de la lecture, ainsi que les attributs que nous pouvons opérer à différentes périodes :
loadstart : démarrer le chargement changement de durée : obtenez la durée de l'audio (l'attribut de durée peut être obtenu à ce moment) ;
progression : téléchargement audio (sera déclenché avec le processus de téléchargement, et l'attribut mis en mémoire tampon peut être obtenu à ce moment) ; 🎜>canplay : L'audio chargé est suffisant pour commencer la lecture (la lecture sera également déclenchée après chaque pause) ;
canplaythrough : tous les audios sont chargés
timeupdate : pendant la lecture (l'attribut currentTime est mis à jour de manière synchrone) ;
recherche : la progression de la lecture en cours est en cours de modification (c'est-à-dire (pour modifier l'attribut currentTime) );
recherchée : la modification de la progression de la lecture en cours est terminée ;
terminée : la lecture est terminée ;
Ceci est le flux général des événements de l'ensemble de l'audio. Il peut y avoir des événements moins utilisés qui ne sont pas répertoriés.
Pendant le processus de déclenchement de l'événement, certaines propriétés peuvent être définies avant le début du chargement de l'audio, telles que : les commandes, la boucle, le volume, etc.
Déterminez l'interface utilisateur et l'interaction du joueur :
Peut-être que chacun a ses propres idées sur l'interface, je n'entrerai donc pas dans les détails ici. Prenons l'interface utilisateur du joueur que j'ai créée comme exemple. décomposez-le
Depuis l'interface, vous pouvez voir les fonctions les plus basiques requises par un joueur :
Lecture/pause, reprise/titre de la chanson/affichage du chanteur, barre de progression de lecture/barre de progression de chargement Fonction de fonctionnement / progression, changement de mode de boucle, mise à jour du texte de progression/durée de la chanson, contrôle de la sourdine/du volume, contrôle de l'état d'affichage de la liste, cliquez sur l'élément de la liste pour changer de chanson
Combiné avec le point de départ de la fourniture des éléments de configuration et des API que nous souhaitons pour répondre aux besoins des utilisateurs, nous pouvons déterminer les éléments de configuration et les éléments d'API exposés que nous souhaitons concevoir :
Éléments de configuration : si la lecture automatique est activée, l'état d'affichage de la liste de chansons par défaut et les paramètres du mode de boucle par défaut
API : lecture/pause/basculement, changement de mode de boucle, sourdine/restauration, statut d'affichage de la liste de commutation, chanson précédente/chanson suivante/chanson coupée, destruction de l'instance actuelle
Établir la structure du projet, commencer à coder :
Parce que nous utilisons webpack, nous emballons le CSS directement dans js afin qu'il puisse être utilisé comme plug-in pour les utilisateurs :
require('./skPlayer.scss');
Extraire les méthodes publiques , il existe de nombreuses méthodes publiques dans le lecteur qui peuvent devoir être extraites, telles que : lorsque vous cliquez sur la barre de progression de la lecture et la barre de progression du volume, vous devez pour calculer la distance entre la souris et l'extrémité gauche de la barre de progression pour le saut de progression. Le temps est obtenu à partir de la durée en secondes. Convertissez l'unité de temps en format d'heure standard, etc. :
const Util = { leftDistance: (el) => { let left = el.offsetLeft; let scrollLeft;while (el.offsetParent) { el = el.offsetParent; left += el.offsetLeft; } scrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;return left - scrollLeft; }, timeFormat: (time) => { let tempMin = parseInt(time / 60); let tempSec = parseInt(time % 60); let curMin = tempMin < 10 ? ('0' + tempMin) : tempMin; let curSec = tempSec < 10 ? ('0' + tempSec) : tempSec;return curMin + ':' + curSec; }, percentFormat: (percent) => {return (percent * 100).toFixed(2) + '%'; }, ajax: (option) => { option.beforeSend && option.beforeSend(); let xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => {if(xhr.readyState === 4){if(xhr.status >= 200 && xhr.status < 300){ option.success && option.success(xhr.responseText); }else{ option.fail && option.fail(xhr.status); } } }; xhr.open('GET',option.url); xhr.send(null); } };
let instance = false;
class skPlayer { constructor(option){ } template(){ } init(){ } bind(){ } prev(){ } next(){ } switchMusic(index){ } play(){ } pause(){ } toggle(){ } toggleList(){ } toggleMute(){ } switchMode(){ } destroy(){ } }
if(instance){ console.error('SKPlayer只能存在一个实例!');return Object.create(null); }else{ instance = true; }
const defaultOption = { ... };this.option = Object.assign({},defaultOption,option);
this.root = this.option.element;this.type = this.option.music.type;this.music = this.option.music.source;this.isMobile = /mobile/i.test(window.navigator.userAgent);
this.toggle = this.toggle.bind(this);this.toggleList = this.toggleList.bind(this);this.toggleMute = this.toggleMute.bind(this);this.switchMode = this.switchMode.bind(this);
this.root.innerHTML = this.template();
this.init();
init(){this.dom = { cover: this.root.querySelector('.skPlayer-cover'), playbutton: this.root.querySelector('.skPlayer-play-btn'), name: this.root.querySelector('.skPlayer-name'), author: this.root.querySelector('.skPlayer-author'), timeline_total: this.root.querySelector('.skPlayer-percent'), timeline_loaded: this.root.querySelector('.skPlayer-line-loading'), timeline_played: this.root.querySelector('.skPlayer-percent .skPlayer-line'), timetext_total: this.root.querySelector('.skPlayer-total'), timetext_played: this.root.querySelector('.skPlayer-cur'), volumebutton: this.root.querySelector('.skPlayer-icon'), volumeline_total: this.root.querySelector('.skPlayer-volume .skPlayer-percent'), volumeline_value: this.root.querySelector('.skPlayer-volume .skPlayer-line'), switchbutton: this.root.querySelector('.skPlayer-list-switch'), modebutton: this.root.querySelector('.skPlayer-mode'), musiclist: this.root.querySelector('.skPlayer-list'), musicitem: this.root.querySelectorAll('.skPlayer-list li') };this.audio = this.root.querySelector('.skPlayer-source');if(this.option.listshow){this.root.className = 'skPlayer-list-on'; }if(this.option.mode === 'singleloop'){this.audio.loop = true; }this.dom.musicitem[0].className = 'skPlayer-curMusic'; }
this.bind();
bind(){this.updateLine = () => { let percent = this.audio.buffered.length ? (this.audio.buffered.end(this.audio.buffered.length - 1) / this.audio.duration) : 0;this.dom.timeline_loaded.style.width = Util.percentFormat(percent); };// this.audio.addEventListener('load', (e) => {// if(this.option.autoplay && this.isMobile){// this.play();// }// });this.audio.addEventListener('durationchange', (e) => {this.dom.timetext_total.innerHTML = Util.timeFormat(this.audio.duration);this.updateLine(); });this.audio.addEventListener('progress', (e) => {this.updateLine(); });this.audio.addEventListener('canplay', (e) => {if(this.option.autoplay && !this.isMobile){this.play(); } });this.audio.addEventListener('timeupdate', (e) => { let percent = this.audio.currentTime / this.audio.duration;this.dom.timeline_played.style.width = Util.percentFormat(percent);this.dom.timetext_played.innerHTML = Util.timeFormat(this.audio.currentTime); });//this.audio.addEventListener('seeked', (e) => {// this.play();//});this.audio.addEventListener('ended', (e) => {this.next(); });this.dom.playbutton.addEventListener('click', this.toggle);this.dom.switchbutton.addEventListener('click', this.toggleList);if(!this.isMobile){this.dom.volumebutton.addEventListener('click', this.toggleMute); }this.dom.modebutton.addEventListener('click', this.switchMode);this.dom.musiclist.addEventListener('click', (e) => { let target,index,curIndex;if(e.target.tagName.toUpperCase() === 'LI'){ target = e.target; }else{ target = e.target.parentElement; } index = parseInt(target.getAttribute('data-index')); curIndex = parseInt(this.dom.musiclist.querySelector('.skPlayer-curMusic').getAttribute('data-index'));if(index === curIndex){this.play(); }else{this.switchMusic(index + 1); } });this.dom.timeline_total.addEventListener('click', (event) => { let e = event || window.event; let percent = (e.clientX - Util.leftDistance(this.dom.timeline_total)) / this.dom.timeline_total.clientWidth;if(!isNaN(this.audio.duration)){this.dom.timeline_played.style.width = Util.percentFormat(percent);this.dom.timetext_played.innerHTML = Util.timeFormat(percent * this.audio.duration);this.audio.currentTime = percent * this.audio.duration; } });if(!this.isMobile){this.dom.volumeline_total.addEventListener('click', (event) => { let e = event || window.event; let percent = (e.clientX - Util.leftDistance(this.dom.volumeline_total)) / this.dom.volumeline_total.clientWidth;this.dom.volumeline_value.style.width = Util.percentFormat(percent);this.audio.volume = percent;if(this.audio.muted){this.toggleMute(); } }); } }
至此,核心代码基本完成,接下来就是自己根据需要完成API部分。
最后我们暴露模块:
module.exports = skPlayer;
一个HTML5音乐播放器就大功告成了 ~ !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!