实现一个HTML5音乐播放器的实例

技术点: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为例进行分解
实现一个HTML5音乐播放器的实例
从界面中可以看出一个播放器所需要的最基础功能:
播放/暂停、封面/歌名/歌手的显示、播放进度条/加载进度条/进度操作功能、循环模式切换、进度文字更新/歌曲时长、静音/音量大小控制、列表显示状态控制、点击列表项切歌功能
再结合我们想要满足用户需求,提供配置项和API的出发点可以得出我们想设计的配置项和暴露的API项:
配置项:自动播放是否开启、默认歌曲列表的显示状态、默认循环模式的设置
API:播放/暂停/toggle、循环模式的切换、静音/恢复、列表显示状态的切换、上一曲/下一曲/切歌、销毁当前实例

确立项目结构,开始编码:
因为使用webpack,所以我们直接将css打包至js内,以便作为插件供用户使用:

require('./skPlayer.scss');

登录后复制

抽离公共方法,在播放器中有很多可能需要抽离的公共方法如:点击播放进度条和音量进度条时需要计算鼠标距离进度条左端的距离以进行进度跳转,时间从duratin中获取到的以秒为单位的时间转换成标准时间格式等等:

实现一个HTML5音乐播放器的实例实现一个HTML5音乐播放器的实例

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  {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);    }};

登录后复制View Code

由于设计之初,考虑到播放器的独特性,设计为只能存在一个实例,设置了一个全局变量以判断当前是否存在实例:

let instance = false;

登录后复制

在使用ES6的情况下,我们将主逻辑放在构造函数内部,将通用性强和API放在公共函数内部:

实现一个HTML5音乐播放器的实例实现一个HTML5音乐播放器的实例

class skPlayer {    constructor(option){    }    template(){    }    init(){    }    bind(){    }    prev(){    }    next(){    }    switchMusic(index){    }    play(){    }    pause(){    }    toggle(){    }    toggleList(){    }    toggleMute(){    }    switchMode(){    }    destroy(){    }}

登录后复制View Code

实例判断,如果存在返回无原型的空对象,因为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();

登录后复制实现一个HTML5音乐播放器的实例实现一个HTML5音乐播放器的实例

    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';    }

登录后复制View Code

事件绑定,主要绑定audio的事件以及操作面板的事件:

            this.bind();

登录后复制实现一个HTML5音乐播放器的实例实现一个HTML5音乐播放器的实例

    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音乐播放器的实例的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2910378.html

(0)
上一篇 2025年3月11日 04:32:07
下一篇 2025年2月24日 09:15:34

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • H5编辑器核心思想的实例分析

    代码和特性在chrome49下测试有效。 文本渲染的本质是对文本节点的渲染,通过浏览器内置的对象Range可以获得选择的起始点、与终止点 var range = getRangeObject();var start = range.star…

    编程技术 2025年3月11日
    200
  • H5本地存储实例详解

    他们可以存储:  数组  json数据  图片  脚本  样式文件  ;   客户端的存储的两个:   1.localStorage  没时间限制的数据存储()     方法有:.localStrage.getItem();localStr…

    编程技术 2025年3月11日
    200
  • html5全新的网络格局

    自从html5诞生之后,就是开始建立了一个标准的原则,那就是所有的技术它必须是面向开放,并不能有专利的一个存在,在整个期间opera捐献了css技术,而google的话则是给开发者提供了视频的webm,本文将带大家来看看html5它是如何带…

    2025年3月11日
    200
  • 带你了解什么是HTML5?

            html5 是对 html 标准的第五次修订。其主要的目标是将互联网语义化,以便更好地被人类和机器阅读,并同时提供更好地支持各种媒体的嵌入。html5 的语法是向后兼容的。      html5草案的前身名为 web app…

    2025年3月11日
    200
  • HTML5新知识

    一、h5新增的主要语义化标签如下: 1、header 页面头部、页眉 2、nav 页面导航 3、atricle 一篇文章 4、section 文章中的章节 5、aside 侧边栏 立即学习“前端免费学习笔记(深入)”; 6、footer 页…

    编程技术 2025年3月11日
    200
  • h5新特性及网页布局实例

    什么是html5:html5 是下一代的html,将成为 html、xhtml 以及 html dom 的新标准。 为 HTML5 建立的一些规则: 新特性应该基于 HTML、CSS、DOM 以及 JavaScript。 减少对外部插件的需…

    2025年3月11日
    200
  • h5表单介绍和表单验证失败问题实例

    这篇文章主要介绍了html5 表单验证失败的提示语问题的相关资料,需要的朋友可以参考下 前言 前端的童鞋在写页面时, 都不可避免的总会踩到 表单验证 这个坑. 这时候, 我们就要跪了, 因为要写一堆 js 来检查. 但是自从 H5 出现后,…

    2025年3月11日
    200
  • html5视频播放教程实例

    pc端主要是利用用flash播放,移动端则通过html5方式实现,这篇文章主要介绍了html5视频播放的相关资料,具有一定的参考价值。 我记得就是前几个月吧,有条消息说YouTube支持了HTML5视频嵌入标签video,好吧,我听说而已,…

    编程技术 2025年3月11日
    200
  • 详解HTML5拖放功能实例

    html5提供专门的拖拽与拖放的api,以后实现这类效果就不必乱折腾了。但是,考虑到opera浏览器似乎对此不感冒,在通用性上有待商榷,所以这里也就简单说一说。拖放(drag 和 drop)是 html5 标准的组成部分。 浏览器支持 In…

    编程技术 2025年3月11日
    200
  • html5的头部head的详解

    移动端的工作已经越来越成为前端工作的重要内容,除了平常的项目开发,html 头部标签功能,特别是meta标签显得非常重要。 HTML文档的head部分,通常包括指定页面标题,为搜索引擎提供关于页面本身的信息,加载样式表,以及加载JavaSc…

    编程技术 2025年3月11日
    200

发表回复

登录后才能评论