SkeyeWebPlayer.js H5免费播放器
- 支持Websocket-RTSP播放;
- 支持 m3u8(HLS) 播放;
- 支持 HTTP-FLV/WS-FLV 播放;
- 支持 HEVC/H265 播放;
- 支持直播和点播播放;
- 支持全屏显示;
- 支持重连播放;
- 具有 H.264 + AAC 编解码器播放功能
- HTTP FLV RTSP低延迟实时流播放 (HLS延时稍大一点,大概在2s—3s左右)
- WS-FLV 通过 WebSocket 实时流播放
- 兼容 Chrome, FireFox, Safari IE11 和 Edge
- 十分低开销,并且通过你的浏览器进行硬件加速
- 支持全屏或比例显示;
- 支持播放器快照截图;
- 支持Android、iOS播放;
本节将实现播放器的控制栏及其功能的实现。效果图如下:
(1)、我把控制栏的每一个小功能放到一个单独的js内,最后在统一到control-bar里面进行统一的管理,这样做管理方便,操作简单。如下图目录结构:
(2)、控制栏所使用的图标可以使用图片,和font字体图标,字体图标到相关的网站下载即可(例如:Iconfont-阿里巴巴矢量图标库):
(3)、控制栏分左、中、右,3个部分,
- 左边部分:播放/暂停按钮、停止、声音、以及一个LIVE的标志。
- 右边部分:视频画面拉伸/按比例显示、快照下载、全屏/还原。
- 中间部分:有一个视频播放的进度条,对视频文件播放时,才显示,(回放,等)
(4)、实现样式
-
首先创建最外部div,和左中右 3个div
let controlBarEl = this.createEl('div', {className: 'vss-control-bar'}); let controlBarLeftEl = this.createEl('div', {className: 'vss-control-bar-left'}); let controlBarConterEl = this.createEl('div', {className: 'vss-control-bar-conter'}); let controlBarrRightEl = this.createEl('div', {className: 'vss-control-bar-right'});
-
播放按钮play-btn.js的相关代码如下:
(1)、dom.js的内容代码放在最下面
(2)、同封装的createEl方法创建好元素,绑定click事件来控制播放的状态
(3)、self.on(‘status’, fun) 来监听 播放状态的变化,来控制显示播放或暂停按钮
/** * play-btn.js */ import {createEl} from '../utils/dom'; class PlayBtn { constructor(self, dom) { this.boxDom = self.boxDom; this.isFill = false; this.isPlaying = false; this.PlayBtnEl = createEl( 'div', {className: 'vss-btn-group vss-pointer'}, {} ); this.IconEl = createEl( 'span', {className: 'vssfont vss-play'}, {title: '播放'} ); this.PlayBtnEl.appendChild(this.IconEl); dom.appendChild(this.PlayBtnEl); this.PlayBtnEl.onclick = (e) => { if (self.url) { if (this.isPlaying) { this.isPlaying = false; this.PlayBtnEl.title = '播放'; this.PlayBtnEl.classList.remove('vss-pause'); this.PlayBtnEl.classList.add('vss-play'); this.pause(self); } else { this.isPlaying = true; this.PlayBtnEl.title = '暂停'; this.PlayBtnEl.classList.remove('vss-play'); this.PlayBtnEl.classList.add('vss-pause'); this.play(self); } } else { console.log('url is empty'); } }; self.on('status', (status) => { if (status === 100) { this.isPlaying = true; this.PlayBtnEl.title = '暂停'; this.PlayBtnEl.classList.remove('vss-play'); this.PlayBtnEl.classList.add('vss-pause'); } }); } // 播放 play(self) { self.play(self.url, 1, self.seekTimeSecs); } // 暂停 pause(self) { self.pause(); } } export default PlayBtn;
-
全屏按钮fullscreen-toggle.js的相关代码如下,在操作全屏与取消全屏控制时需要注意:
(1)、开启全屏是使用 this.boxDom.requestFullscreen() ,this.boxDom是表示播放器容器的这个元素,对他调用requestFullscreen方法。
(2)、但是在取消全屏的时候 是使用 document.exitFullscreen(); 是对document进行操作,这两个操作的对象需要注意一下,别搞错了。
/** * fullscreen-toggle.js */ import {createEl} from '../utils/dom'; class FullscreenToggle { constructor(self, dom) { this.boxDom = self.boxDom; this.isFullScreen = false; this.fullScreenBtnEl = createEl('div', {className: 'vss-full-screen-btn vss-pointer'}, {}); this.fullScreenIconEl = createEl('span', {className: 'vssfont vss-fullscreen'}, { title: '全屏' }); this.fullScreenBtnEl.appendChild(this.fullScreenIconEl); dom.appendChild(this.fullScreenBtnEl); this.fullScreenBtnEl.onclick = (e) => { if (this.isFullScreen) { // 取消全屏 this.isFullScreen = false; self.callbackFunc('unFull'); this.fullScreenIconEl.title = '全屏'; this.fullScreenIconEl.classList.remove('vss-cancel-fullscreen'); this.fullScreenIconEl.classList.add('vss-fullscreen'); this.exitFullScreen(); } else { // 全屏 this.isFullScreen = true; self.callbackFunc('full'); this.fullScreenIconEl.title = '取消全屏'; this.fullScreenIconEl.classList.remove('vss-fullscreen'); this.fullScreenIconEl.classList.add('vss-cancel-fullscreen'); this.requestFullscreen(); } }; // 监听播放器是否为全屏状态 // document.addEventListener('fullscreenchange', function (e) { // // }); } // 全屏 requestFullscreen() { if (this.boxDom.requestFullscreen) { this.boxDom.requestFullscreen(); } else if (this.boxDom.mozRequestFullScreen) { this.boxDom.mozRequestFullScreen(); } else if (this.boxDom.webkitRequestFullscreen) { this.boxDom.webkitRequestFullscreen(); } else if (this.boxDom.msRequestFullscreen) { this.boxDom.msRequestFullscreen(); } } // 取消全屏 exitFullScreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); } } } export default FullscreenToggle;
-
其他的我就不一一描述了,与上面的写法基本差不多,最后在放一个dom.js。
export function isObject(value) { return !!value && typeof value === 'object'; } export function isEl(value) { return isObject(value) && value.nodeType === 1; } export function isTextNode(value) { return isObject(value) && value.nodeType === 3; } export function normalizeContent(content) { // First, invoke content if it is a function. If it produces an array, // that needs to happen before normalization. if (typeof content === 'function') { content = content(); } // Next up, normalize to an array, so one or many items can be normalized, // filtered, and returned. return (Array.isArray(content) ? content : [content]).map(value => { // First, invoke value if it is a function to produce a new value, // which will be subsequently normalized to a Node of some kind. if (typeof value === 'function') { value = value(); } if (isEl(value) || isTextNode(value)) { return value; } if (typeof value === 'string' && (/\S/).test(value)) { return document.createTextNode(value); } }).filter(value => value); } export function appendContent(el, content) { normalizeContent(content).forEach(node => el.appendChild(node)); return el; } /** * 创建元素并应用属性、属性和插入内容. * @param {string} [tagName='div'] 要创建的标记的名称. * @param {Object} [properties={}] 要应用的元素属性. * @param {Object} [attributes={}] 要应用的元素属性. * @param {string} [content] 内容描述符对象. * @return {Element} 创建的元素. */ export function createEl(tagName = 'div', properties = {}, attributes = {}, content) { const el = document.createElement(tagName); Object.getOwnPropertyNames(properties).forEach(function (propName) { const val = properties[propName]; if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') { // log.warn('Setting attributes in the second argument of createEl()\n' + // 'has been deprecated. Use the third argument instead.\n' + // `createEl(type, properties, attributes). Attempting to set ${propName} to ${val}.`); el.setAttribute(propName, val); } else if (propName === 'textContent') { // textContent(el, val); } else if (el[propName] !== val || propName === 'tabIndex') { el[propName] = val; } }); Object.getOwnPropertyNames(attributes).forEach(function (attrName) { el.setAttribute(attrName, attributes[attrName]); }); if (content) { appendContent(el, content); } return el; }
val;
}
});
Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
el.setAttribute(attrName, attributes[attrName]);
});
if (content) {
appendContent(el, content);
}
return el;
}
- 如有错误还请大家指正。