技術點:ES6+Webpack+HTML5 Audio+Sass
這裡,我們將一步步的學習如何從零去實現一個H5音樂播放器。
先來看看最終的實現效果:Demo連結
接下來就步入正題:
要做一個音樂播放器就要非常了解在Web中音訊播放的方式,通常都採用HTML5的audio標籤
關於audio標籤,它有大量的屬性、方法和事件,在這裡我就做一個大致的介紹。
屬性:
src:必需,音訊來源;
controls:常見,設定後顯示瀏覽器預設的audio控制面板,不設定預設隱藏audio標籤;
autoplay:常見,設定後自動播放音訊(行動裝置不支援);
loop:常見,設定後音訊將循環播放;
preload:常見,設定音訊預載(行動端不支援);
volume:少見,設定或返回音訊大小,值為0-1之間的浮點數(行動端不支援);
muted:少見,設定或返回靜音狀態;
duration:少見,回傳音訊時長;
currentTime:少見,設定或返回當前播放時間;
paused:少見,返回當前播放狀態,是否暫停;
buffered:少見,一個TimeRanges對象,包含已緩衝的時間段信息,即加載進度。此物件包含一個屬性length,傳回一個從0開始的數表示目前緩衝了多少段音訊;還包含兩個方法,start、end,分別需要傳入一個參數,即傳入音訊已載入的第幾段,從0開始。 start返回該段的起始時間,end返回該段的終點時間。範例:即傳入0,第一段的起始是0,終止時間是17,單位秒;
屬性就介紹到這裡,可能還有一些比較少用的屬性如:playbackRate等,在影片播放中可能會用到,我就暫不講解。
方法:
play():開始播放音訊;
pause():暫停播放音訊;
事件:
canplay:目前音訊可以開始播放(只載入了部分buffered,並未全部載入完成);
canplaythrough:可以無停頓播放(即音訊全部載入完成);
durationchange:音訊時長發生變化;
ended:播放結束;
error:發生錯誤;
pause:播放暫停;
play:播放開始;
progress:音訊下載過程中觸發,事件觸發過程中可以透過存取audio的buffered屬性取得載入進度;
seeking:音訊跳躍中觸發,即為修改currentTime時;
seeked:音訊跳躍完成時觸發,即為修改完成currentTime時;
timeupdate:音訊播放過程中觸發,同時currentTime屬性在同步更新;
事件就介紹到這裡,可能還有一些不常用的事件暫不講解。
最後再講解一個音訊從開始載入到播放結束過程中,所觸發的事件流以及我們在不同時間段可以操作的屬性:
loadstart:開始載入;
durationchange:取得到音訊時長(此時可取得duration屬性);
progress:音訊下載中(將伴隨下載過程一直觸發,此時可以取得buffered屬性);
canplay:所載入的音訊足夠開始播放(每次暫停後開始播放也會觸發);
canplaythrough:音訊全部載入完成;
timeupdate:播放過程中(currentTime屬性伴隨著同步更新);
seeking:修改目前播放進度中(即為修改currentTime屬性);
seeked:修改目前播放進度完成;
ended:播放完成;
這就是整個音訊的大致事件流,可能有一些少用的事件沒有列舉。
在事件觸發過程中,有一些屬性在音訊還沒開始載入的時候就可以設置,如:controls、loop、volume等等;確定整體結構:
因為自己是做成插件的方式發佈在npm上供他人使用的,所以我們就採用面向對象的方式進行代碼編寫,又因為用戶的需求不一,所以在設計之初就暴露出大量的API和配置項以滿足大部分使用者的需求。
這裡因為自己更習慣es6的語法,就全程以es6為基礎進行開發,同時為了開發效率,又使用了sass進行css的編寫,最後還使用了webpack和webpack-dev-server用以編譯es6和sass,專案打包,建構本地伺服器。確定播放器UI和互動:
可能關於介面每個人都有自己的想法,這裡就不過多贅述了,以我做好的播放器UI為例進行分解
從介面可以看出一個播放器所需的最基本功能:
播放/暫停、封面/歌名/歌手的顯示、播放進度條/載入進度條/進度操作功能、循環模式切換、進度文字更新/歌曲時長、靜音/音量大小控制、列表顯示狀態控制、點擊列表項目切歌功能
再結合我們想要滿足用戶需求,提供配置項目和API的出發點可以得出我們想設計的配置項目和暴露的API項目:
配置項目:自動播放是否開啟、預設歌曲清單的顯示狀態、預設循環模式的設定
API:播放/暫停/toggle、循環模式的切換、靜音/恢復、清單顯示狀態的切換、上一曲/下一曲/切歌、銷毀目前實例-
#確立專案結構,開始編碼:
因為使用webpack,所以我們直接將css打包至js內,以便作為插件供用戶使用:require('./skPlayer.scss');
抽離公共方法,在播放器中有很多可能需要抽離的公共方法如:點擊播放進度條和音量進度條時需要計算滑鼠距離進度條左端的距離以進行進度跳轉,時間從duratin中獲取到的以秒為單位的時間轉換成標準時間格式等等:
#View Codeconst 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 {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
由於設計之初,考慮到播放器的獨特性,設計為只能存在一個實例,設定了一個全域變數以判斷目前是否存在實例:
let instance = false;
在使用ES6的情況下,我們將主邏輯放在建構子內部,將通用性強和API放在公共函數內部:
#View Codeclass skPlayer { constructor(option){ } template(){ } init(){ } bind(){ } prev(){ } next(){ } switchMusic(index){ } play(){ } pause(){ } toggle(){ } toggleList(){ } toggleMute(){ } switchMode(){ } destroy(){ } }
#實例判斷,如果存在返回無原型的空對象,因為ES6構造函數內預設返回帶原型的實例:
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);
一些公共的API內部this指向在預設情況下指向實例,但為了減少程式碼量,將操作介面上的功能與API呼叫一套程式碼,在綁定事件的時候this指向會改變,所以透過bind的方式綁定this,當然也可以在綁定事件的時候使用箭頭函數:
this.toggle = this.toggle.bind(this);this.toggleList = this.toggleList.bind(this);this.toggleMute = this.toggleMute.bind(this);this.switchMode = this.switchMode.bind(this);
接下來,我們就使用ES6字串模板開始產生HTML,插入到頁面中:
this.root.innerHTML = this.template();
接下來初始化,初始化過程中將常用DOM節點綁定,初始化配置項,初始化操作介面:
this.init();
View Codeinit(){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(); } }); } }
##### #View Code######至此,核心代码基本完成,接下来就是自己根据需要完成API部分。
最后我们暴露模块:module.exports = skPlayer;
一个HTML5音乐播放器就大功告成了 ~ !
以上是實作一個HTML5音樂播放器的實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

H5的高級技巧包括:1.利用進行複雜圖形繪製,2.使用WebWorkers提升性能,3.通過WebStorage增強用戶體驗,4.實現響應式設計,5.利用WebRTC實現實時通信,6.進行性能優化和最佳實踐。這些技巧幫助開發者構建更動態、互動和高效的Web應用。

H5(HTML5)將通過新元素和API提升網頁內容和設計。 1)H5增強了語義化標記和多媒體支持。 2)它引入了Canvas和SVG,豐富了網頁設計。 3)H5的工作原理是通過新標籤和API擴展HTML功能。 4)基本用法包括使用創建圖形,高級用法涉及WebStorageAPI。 5)開發者需注意瀏覽器兼容性和性能優化。

H5帶來了多項新功能和能力,極大提升了網頁的互動性和開發效率。 1.語義化標籤如、增強了SEO。 2.多媒體支持通過和標籤簡化了音視頻播放。 3.Canvas繪圖提供了動態圖形繪製工具。 4.本地存儲通過localStorage和sessionStorage簡化了數據存儲。 5.地理位置API便於開發基於位置的服務。

HTML5帶來了五個關鍵改進:1.語義化標籤提升了代碼清晰度和SEO效果;2.多媒體支持簡化了視頻和音頻嵌入;3.表單增強簡化了驗證;4.離線與本地存儲提高了用戶體驗;5.畫布與圖形功能增強了網頁的可視化效果。

HTML5的核心特性包括語義化標籤、多媒體支持、離線存儲與本地存儲、表單增強。 1.語義化標籤如、等,提升代碼可讀性和SEO效果。 2.和標籤簡化多媒體嵌入。 3.離線存儲和本地存儲如ApplicationCache和LocalStorage,支持無網絡運行和數據存儲。 4.表單增強引入新輸入類型和驗證屬性,簡化處理和驗證。

H5提供了多種新特性和功能,極大地增強了前端開發的能力。 1.多媒體支持:通過和元素嵌入媒體,無需插件。 2.畫布(Canvas):使用元素動態渲染2D圖形和動畫。 3.本地存儲:通過localStorage和sessionStorage實現數據持久化存儲,提升用戶體驗。

H5和HTML5是不同的概念:HTML5是HTML的一個版本,包含新元素和API;H5是基於HTML5的移動應用開發框架。 HTML5通過瀏覽器解析和渲染代碼,H5應用則需要容器運行並通過JavaScript與原生代碼交互。

HTML5的關鍵元素包括、、、、、等,用於構建現代網頁。 1.定義頭部內容,2.用於導航鏈接,3.表示獨立文章內容,4.組織頁面內容,5.展示側邊欄內容,6.定義頁腳,這些元素增強了網頁的結構和功能性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

禪工作室 13.0.1
強大的PHP整合開發環境