feat: 集成edu-core模块并重构课程详情页视频播放

- 添加edu-core本地依赖,用于视频播放组件
- 重构课程详情页,使用CourseVideo组件替换原有视频播放逻辑
- 优化课程列表页布局和样式,修复边框单位问题
- 更新manifest.json支持多方向屏幕旋转
This commit is contained in:
2026-02-09 10:29:59 +08:00
parent 671b7eb63d
commit 0e900d19be
33 changed files with 11533 additions and 98 deletions

View File

@@ -0,0 +1,454 @@
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/*手势事件处理*/
var YbGesture = /*#__PURE__*/function () {
function YbGesture(player, config) {
_classCallCheck(this, YbGesture);
this.player = player;
this.config = config;
this.disabled = false; //禁用手势事件
this._touchstartX = null;
this._touchstartY = null;
this._touchmoveX = null;
this._touchmoveY = null;
this._clickTime = null;
this._touchTime = null;
this._threshold = 20;
this._singleTouchTime = 150; //单击间隔时间
this._longTouchTime = 500; //长按间隔时间
this._mousedown = null;
this._isMove = null; //是否滑动
this._isVolume = null; //是否音量调节
this._isLight = null; //是否亮度调节
this._isProgress = null; //是否进度调节
this._seekTime = null; //跳转时间
this._seekVolume = null; //改变音量
this._seekLight = null; //改变亮度
this._touchTimer = null; //触摸定时器
this._longTimer = null; //长按定时器
this._centerTimer = null; //中间元素隐藏定时器
}
return _createClass(YbGesture, [{
key: "resetTouch",
value: function resetTouch() {
this._touchstartX = null;
this._touchstartY = null;
this._touchmoveX = null;
this._touchmoveY = null;
this._touchTime = null;
this._clickTime = null;
this._isMove = null;
this._isVolume = null;
this._isLight = null;
this._isProgress = null;
this._seekTime = null;
this._seekVolume = null;
this._seekLight = null;
}
}, {
key: "touchstart",
value: function touchstart(e) {
var _this = this;
if (this.stopPropagation(e)) return;
this._clearTouchTimer();
this._clearLongTimer();
var touch = e.touches[0];
this._touchstartX = touch.pageX;
this._touchstartY = touch.pageY;
this._clickTime++;
if (this._clickTime == 1) {
//第一次点击
this._touchTimer = window.setTimeout(function () {
_this._touchTime = _this._singleTouchTime;
}, this._singleTouchTime);
this._longTimer = window.setTimeout(function () {
if (_this._touchmoveX <= _this._threshold && _this._touchmoveY <= _this._threshold && !_this.config.disableLongPress) {
//当滑动距离不超过阙值时,且为禁止长按,才会执行长按
_this._touchTime = _this._longTouchTime;
_this.longPress(); //长按事件
}
}, this._longTouchTime);
}
}
}, {
key: "touchmove",
value: function touchmove(e) {
if (this.stopPropagation(e)) return;
if (this._clickTime > 0) {
var touch = e.touches[0];
this._touchmoveX = Math.abs(touch.pageX - this._touchstartX);
this._touchmoveY = Math.abs(touch.pageY - this._touchstartY);
//判断用户是否进行滑动,只要判断一次滑动,当前触摸事件就一直是滑动
if (!this._isMove) this._isMove = this._touchmoveY > this._threshold || this._touchmoveX > this._threshold;
//第二次点击 未开启全屏 未开启非全拼手势操作 锁屏中 滑动距离不大于阙值 触摸时间超过长按时间
if (this._clickTime == 2 || !this._isMove || this._touchTime == this._longTouchTime || !this.player.getFullscreen() && this.config.disableUnFullscreenEvent || this.player.disabled || this.disabled) return;
//根据视频方向,反转触摸位置和滑动距离
var container = this.player.container;
var containerWidth = container.offsetWidth;
var containerHeight = container.offsetHeight;
var touchX = this._touchstartX;
var touchY = this._touchstartY;
var offsetX = this._touchmoveX;
var offsetY = this._touchmoveY;
//点击在左边并且y轴滑动距离比x轴滑动距离大的时候执行调节亮度操作
if (touchX < containerWidth / 2 && offsetY > offsetX && !this._isVolume && !this._isProgress && !this.config.disableLight) {
this._isLight = true;
var initial = this.config.initialLight;
var max = 1;
var deltaY = touch.pageY - this._touchstartY;
// 计算滑动距离与容器宽度的比例
var percentDelta = offsetY / containerHeight;
// 根据比例和滑动可控制最大时长计算时间变化量
var delta = percentDelta * max;
// 计算新的时间位置
this._seekLight = deltaY < 0 ? initial + delta : initial - delta;
this._seekLight = this._seekLight > max ? max : this._seekLight < 0 ? 0 : this._seekLight;
this.setLight(this._seekLight);
}
//点击在右边并且y轴滑动距离比x轴滑动距离大的时候执行调节音量操作
if (touchX > containerWidth / 2 && offsetY > offsetX && !this._isLight && !this._isProgress && !this.config.disableVolume) {
this._isVolume = true;
var initial = this.config.initialVolume;
var max = 1;
var deltaY = touch.pageY - this._touchstartY;
// 计算滑动距离与容器宽度的比例
var percentDelta = offsetY / containerHeight;
// 根据比例和滑动可控制最大时长计算时间变化量
var delta = percentDelta * max;
// 计算新的时间位置
this._seekVolume = deltaY < 0 ? initial + delta : initial - delta;
this._seekVolume = this._seekVolume > max ? max : this._seekVolume < 0 ? 0 : this._seekVolume;
this.setVolume(this._seekVolume);
}
//y轴滑动距离比x轴滑动距离小的时候执行进度调节 不能为直播源 视频必须加载到数据
var video = this.player.video;
var duration = this.player.getDuration();
if (offsetY < offsetX && !this._isLight && !this._isVolume && !this.player.isLive && duration && !this.config.disableProgress) {
this._isProgress = true;
var deltaX = touch.pageX - this._touchstartX;
// 计算滑动距离与容器宽度的比例
var percentDelta = offsetX / containerWidth;
// 根据比例和滑动可控制最大时长计算时间变化量
var timeDelta = percentDelta * Math.min(180, duration);
// 计算新的时间位置
this._seekTime = deltaX > 0 ? video.currentTime + timeDelta : video.currentTime - timeDelta;
this._seekTime = this._seekTime > duration ? duration : this._seekTime < 0 ? 0 : this._seekTime;
this.setProgress(this._seekTime);
}
}
}
}, {
key: "touchend",
value: function touchend(e) {
var _this2 = this;
if (this.stopPropagation(e)) return;
this._clearTouchTimer();
this._clearLongTimer();
//当触摸事件等于
if (this._touchTime == this._longTouchTime) this.stopLongPress(); //停止长按
//点击次数大于零并且触摸时间小于单击时间并且滑动距离不超过阙值
else if (this._clickTime > 0 && this._touchTime < this._singleTouchTime && this._touchmoveX <= this._threshold && this._touchmoveY <= this._threshold) {
if (this._clickTime == 1 && !this.config.disableSingleClick) {
//第一次点击
this._touchTimer = window.setTimeout(function () {
_this2.singleClick();
}, this._singleTouchTime);
} else if (this._clickTime == 2 && !this.config.disableDoubleClick) this.doubleClick(); //第二次点击
else this.resetTouch();
} else {
var video = this.player.video;
if (this._isProgress && this._seekTime >= 0 && video) video.currentTime = this._seekTime;
if (this._isLight && this._seekLight >= 0) {
this.config.initialLight = this._seekLight; //更新初始化亮度,注意这并不代表系统亮度被改变
var data = {
seekLight: this._seekLight
};
this.player.emit('seeklight', this._seekLight);
}
if (this._isVolume && this._seekVolume >= 0) {
//更新初始化音量,注意这并不代表系统音量被改变
this.config.initialVolume = this._seekVolume;
var data = {
seekVolume: this._seekVolume
};
this.player.emit('seekvolume', this._seekVolume);
}
this.resetTouch();
}
}
}, {
key: "singleClick",
value: function singleClick() {
//单击事件
this.resetTouch();
if (this.player.controls) {
if (this.player.getControls()) this.player.hideControls();else this.player.showControls();
}
this.player.emit('singleclick');
}
}, {
key: "doubleClick",
value: function doubleClick() {
//双击事件
this.resetTouch();
this.player.toggle();
this.player.emit('doubleclick');
}
}, {
key: "longPress",
value: function longPress() {
//长按事件
this.setPlaybackRate(2.0);
this.player.emit('longpress');
}
}, {
key: "stopLongPress",
value: function stopLongPress() {
//停止长按事件
this.resetTouch();
this.setPlaybackRate(1.0);
this.player.emit('stoplongpress');
}
//注册手势事件
}, {
key: "load",
value: function load() {
var _this3 = this;
var container = this.player.container;
var wrapperEl = container.getElementsByClassName('yb-player-wrapper')[0];
//绑定触摸监听
wrapperEl.ontouchstart = function (e) {
_this3.touchstart(e);
};
wrapperEl.ontouchmove = function (e) {
_this3.touchmove(e);
};
wrapperEl.ontouchend = function (e) {
_this3.touchend(e);
};
wrapperEl.ontouchcancel = function (e) {
_this3.touchend(e);
};
//电脑端模拟触摸
wrapperEl.onmousedown = function (e) {
if ('ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch) return; //设备支持触屏则不触发mousedown
_this3._mousedown = true;
_this3.touchstart({
target: e.target,
touches: [{
pageX: e.pageX,
pageY: e.pageY
}]
});
};
wrapperEl.onmousemove = function (e) {
if (!_this3._mousedown) return;
_this3.touchmove({
target: e.target,
touches: [{
pageX: e.pageX,
pageY: e.pageY
}]
});
};
wrapperEl.onmouseup = function (e) {
if (!_this3._mousedown) return;
_this3._mousedown = false;
_this3.touchend(e);
};
}
//注销手势事件
}, {
key: "unload",
value: function unload() {
this._clearTouchTimer();
this._clearLongTimer();
this._clearCenterTimer();
var container = this.player.container;
var wrapperEl = container.getElementsByClassName('yb-player-wrapper')[0];
if (wrapperEl) {
wrapperEl.ontouchstart = null;
wrapperEl.ontouchmove = null;
wrapperEl.ontouchend = null;
wrapperEl.onmousedown = null;
wrapperEl.onmousemove = null;
wrapperEl.onmouseup = null;
wrapperEl = null;
}
}
}, {
key: "setConfig",
value: function setConfig(key, value) {
this.config[key] = value;
}
}, {
key: "disable",
value: function disable() {
this.disabled = true;
}
}, {
key: "enable",
value: function enable() {
this.disabled = false;
}
//设置倍速
}, {
key: "setPlaybackRate",
value: function setPlaybackRate(playbackRate) {
var video = this.player.video;
if (!video) return;
if (playbackRate == video.playbackRate) return;
video.playbackRate = playbackRate;
// if ( ![1, 1.0].includes(playbackRate) ) {
// var rateEl = document.createElement('DIV')
// rateEl.innerHTML = `
// <div class="yb-player-rate">
// <div class="yb-player-rate-icon">
// <i></i><i></i><i></i>
// </div>
// <span class="yb-player-rate-span">${playbackRate + '倍速播放中'}</span>
// </div>
// `
// var wrapperEl = this.player.container.getElementsByClassName('yb-player-wrapper')[0]
// if ( wrapperEl ) wrapperEl.appendChild(rateEl)
// } else {
// var rateEl = this.player.container.getElementsByClassName('yb-player-rate')[0]
// if ( rateEl )rateEl.remove()
// }
}
//设置音量
}, {
key: "setVolume",
value: function setVolume(volume) {
var _this4 = this;
this._clearCenterTimer();
var container = this.player.container;
var wrapperEl = container.getElementsByClassName('yb-player-wrapper')[0];
var div = container.getElementsByClassName('yb-player-center-value')[0];
if (!div) {
div = document.createElement('DIV');
div.setAttribute('class', 'yb-player-center yb-player-center-value');
wrapperEl.appendChild(div);
}
div.innerHTML = "\n\t\t\t<span>\u97F3\u91CF</span>\n\t\t\t<span>".concat((volume / 1 * 100).toFixed(0), "%</span>\n\t\t");
this._centerTimer = window.setTimeout(function () {
_this4.hideCenterValue();
}, 1000);
}
//设置亮度
}, {
key: "setLight",
value: function setLight(light) {
var _this5 = this;
this._clearCenterTimer();
var container = this.player.container;
var wrapperEl = container.getElementsByClassName('yb-player-wrapper')[0];
var div = container.getElementsByClassName('yb-player-center-value')[0];
if (!div) {
div = document.createElement('DIV');
div.setAttribute('class', 'yb-player-center yb-player-center-value');
wrapperEl.appendChild(div);
}
div.innerHTML = "\n\t\t\t<span>\u4EAE\u5EA6</span>\n\t\t\t<span>".concat((light / 1 * 100).toFixed(0), "%</span>\n\t\t");
this._centerTimer = window.setTimeout(function () {
_this5.hideCenterValue();
}, 1000);
}
//设置进度
}, {
key: "setProgress",
value: function setProgress(time) {
var _this6 = this;
this._clearCenterTimer();
var container = this.player.container;
var video = this.player.video;
var wrapperEl = container.getElementsByClassName('yb-player-wrapper')[0];
var div = container.getElementsByClassName('yb-player-center-value')[0];
if (!div) {
div = document.createElement('DIV');
div.setAttribute('class', 'yb-player-center yb-player-center-value');
wrapperEl.appendChild(div);
}
div.innerHTML = "\n\t\t\t".concat(YbPlayer.timeFormat(time), " / ").concat(YbPlayer.timeFormat(this.player.getDuration()), "\n\t\t");
this._centerTimer = window.setTimeout(function () {
_this6.hideCenterValue();
}, 1000);
}
//删除手势事件产生的中间控件
}, {
key: "hideCenterValue",
value: function hideCenterValue() {
var div = this.player.container.getElementsByClassName('yb-player-center-value')[0];
if (div) {
div.remove();
div = null;
}
}
/**
* 阻止冒泡
* @param e 点击实例
*/
}, {
key: "stopPropagation",
value: function stopPropagation(e) {
var container = this.player.container;
var gestureEls = container.getElementsByClassName('yb-player-gesture'); //允许手势事件冒泡元素标记
var isGesture = false; //是否点击了非手势控制标记的元素
for (var i = 0; i < gestureEls.length; i++) {
isGesture = gestureEls[i].contains(e.target); //对比元素
if (isGesture) break; //如果找到了,打断循环
}
if (isGesture) return false; //允许手势事件
var danmuEl = container.getElementsByClassName('yb-player-danmu')[0];
var subtitleEl = container.getElementsByClassName('yb-player-subtitle')[0];
var panoEl = container.getElementsByClassName('yb-player-pano')[0];
var video = this.player.video;
// console.log('target', e.target);
// console.log('video', video.contains(e.target));
// console.log('danmuEl', danmuEl.contains(e.target));
// console.log('subtitleEl', subtitleEl.contains(e.target));
if (video && video.contains(e.target) || danmuEl && danmuEl.contains(e.target) || subtitleEl && subtitleEl.contains(e.target) || panoEl && panoEl.contains(e.target)) return false;
return true;
}
/***** 清除定时器 *****/
}, {
key: "_clearTouchTimer",
value: function _clearTouchTimer() {
if (this._touchTimer) {
window.clearTimeout(this._touchTimer);
this._touchTimer = null;
}
}
}, {
key: "_clearLongTimer",
value: function _clearLongTimer() {
if (this._longTimer) {
window.clearTimeout(this._longTimer);
this._longTimer = null;
}
}
}, {
key: "_clearCenterTimer",
value: function _clearCenterTimer() {
if (this._centerTimer) {
window.clearTimeout(this._centerTimer);
this._centerTimer = null;
}
}
}]);
}(); //兼容new Function为了挂载到window对象上
if (typeof window != 'undefined') {
window.YbGesture = YbGesture;
}