uniapp 基于xgplayer(西瓜视频) + renderjs开发,实现APP视频播放

server/2024/12/27 21:08:30/

背景:在uniapp中因原生video组件功能有限,选择引入xgplayer库来展示视频播放等功能。并且APP端无法操作dom,所以使用了renderjs

其他的不多说,主要列举一下renderjs中需要注意的点:
1、使用:在标签后,添加<script module="xgPlayerModule" lang="renderjs"></script >,然后有关操作dom的代码都写在script 标签里面。其中module的值是自定义的,后续会用这个值来调用renderjs的方法。

2、普通 script 标签是逻辑层,带renderjs的 script 标签是视图层

3、逻辑层向视图层传值:在 template 某元素上添加 :属性名=“vue 变量”:change:属性名=“renderjs 模块名.方法名” (其中 vue 变量 为 Vue 组件中的某个数据, renderjs 模块名 为之前定义的 module 属性的值,当 vue 变量 值改变时会触发 renderjs模块名.方法名 的方法)。例如:

<view :iosTimes="iosTimes" :change:iosTimes="xgPlayerModule.changeTimes"></view><script module="xgPlayerModule" lang="renderjs">export default {data(){return {renderIosTimes: null}},methods: {changeTimes() { // 当检测到iosTimes变化时,触发此方法,重新赋值后,保存在renderjs里面的renderIosTimes 变量中,因为后面renderjs里面的其他方法要使用这个值。this.renderIosTimes = this.iosTimes}}}
</script>  

4、**视图层向逻辑层传参:**在 template 元素的事件绑定中使用 @事件=“renderjs 模块名.方法名” ,通过该方式触发 renderjs 中的方法,然后在这个方法中可以使用 this.$ownerinstance.callmethod('vue 组件中的方法名', 参数) 来调用普通 Vue 组件中的方法并传值。

this.$ownerInstance.callMethod('playerMethods')

接下来就是在renderjs中,通过xgplayer创建视频,并且完成交互

准备:
npm install xgplayer --save

以下是完整的代码案例:
video.vue中调用xgplayer组件

 <xg-player :data-idkey="modId" ref="video" :videoConfig="videoConfig" ></xg-player>import xgPlayer from '@/components/player/xgplayer';
<script>export default {data(){return {videoConfig: {videoUrl: '', // 播放地址lastPlayTime: '' // 上次播放时间}	}},methods: {changeTimes() { // 当检测到iosTimes变化时,触发此方法,重新赋值后,保存在renderjs里面的renderIosTimes 变量中,因为后面renderjs里面的其他方法要使用这个值。this.renderIosTimes = this.iosTimes}},onHide: function() { // 退出应用时调用this.$refs['video'].beforeLeave()  // 调用子组件的方法,暂停视频播放}}
</script>  

xgplayer.vue组件中:

<template><view><!-- 视频 --><view:id='videoId'class="mse-box":style="customStyle"v-if="type === 'VOD'":conEnd="conEnd" :change:conEnd="xgPlayerModule.initVideo"></view><view :iosTimes="iosTimes" :change:iosTimes="xgPlayerModule.changeTimes"></view><view :modOpenTrial="modOpenTrial" :change:modOpenTrial="xgPlayerModule.changeModOpenTrial"></view><view :playOrPauseStatus="playOrPauseStatus" :change:playOrPauseStatus="xgPlayerModule.playOrPauseVideoRenderjs"></view></view>
</template><!-- 逻辑层 -->
<script>
export default {name: 'xgPlayerHls',data: function() {return {config: {id: this.videoId,url: '',fluid: true,playbackRate: [0.75, 1, 1.5, 2],defaultPlaybackRate: 1,definitionActive: 'click',poster: '',volume: 1,autoplay: false, // 手动点击播放,节省用户流量playsinline: true,lastPlayTime: 0, //视频起播时间(单位:秒)lastPlayTimeHideDelay: 3,enableVideoDbltouch: true,rotateFullscreen: true,// rotate: {//     innerRotate: true,//     clockwise: false// },fitVideoSize: 'auto'},inFullscreen: false,inLandscape: false,conEnd: null,playOrPauseStatus: 'pause'};},components: {},computed: {// h5通过监听屏幕角度去写入样式customStyle() {const that = this;if (that.inFullscreen && that.inLandscape) {return {height: '100vh !important',minWidth: '100%',width: '100% !important',left: '0%',transform: 'rotate(0deg)'};} else if (that.inLandscape) {return {width: '100% !important',height: '400rpx !important'};} else {return {width: '100%',height: '400rpx'};}}},props: {rootStyle: {type: Object,default() {return {};}},iosTimes: {type: Boolean,default() {return false;}},videoConfig: {type: Object,default() {return {videoUrl: '', lastPlayTime: 0};}},modOpenTrial: {type: Boolean,default() {return true;}},modDrag: {type: Boolean,default() {return true;}},fastForward: {type: Boolean,default() {return true;}},type: {type: String,default() {return 'VOD';}},videoId: {type: String,default() {return 'mse';}}},methods: {beforeLeave() { // 离开页面暂停视频播放this.playOrPauseStatus = 'pause'},playVideo() {this.playOrPauseStatus = 'play'},pauseVideo() {this.playOrPauseStatus = 'pause'},handleOrientation() {const orientation = window.orientation;console.log('orientation=当设备的方向发生变化时触发的事件===', orientation);switch (orientation) {case 0:// 竖屏this.inLandscape = false;break;case 90:// 左横屏this.inLandscape = true;break;case -90:// 右横屏this.inLandscape = true;break;case 180:// 倒立break;default:// 未知break;}},fullScreenMe() { // 进入全屏this.inFullscreen = true;this.$emit('on-goLandscape', 'ON');},exitFullScreenMe() { // 退出全屏this.inFullscreen = false;this.$emit('on-goLandscape', 'OFF');},playTimeUpdate(currentTime) { // timeupdate播放中// console.log('播放中=============');this.$emit('playerVideo', currentTime);},openTrialMe() {// 弹框有问题this.$dialog.alert({width: '80%',confirmButtonColor: '#00aeef',confirmButtonText: this.$t('mall_10'),message: this.$t('see_end')});},playerMethods() { // 播放console.log('播放============');this.playOrPauseStatus = 'play'this.$emit('videoPlay')},playerPauseMethods() { // 暂停console.log('暂停============');this.playOrPauseStatus = 'pause'this.$emit('videoPause')},init() {if (this.videoConfig.videoUrl) {if (this.type === 'VOD') {this.config.id = this.videoId;this.config.lastPlayTime = this.videoConfig.lastPlayTime;this.config.url = this.videoConfig.videoUrl;this.config.autoplay =this.videoConfig.autoplaythis.config.ignores = this.fastForward ? [] : ['progress'];if (this.videoConfig.duration) {this.config.duration = this.videoConfig.duration;}// m3u8 格式播放if (this.videoConfig.videoUrl.indexOf('m3u8') !== -1) {this.config.preloadTime = 15; // 预加载时间15sthis.config.minCachedTime = 5; // 最小缓存时间// iOS手机不兼容此项属性,故作此判断// 使用 uni.getSystemInfoSync() 获取系统信息const systemInfo = uni.getSystemInfoSync();const platform = systemInfo.platform;if (platform === 'android') {this.config.useHls = true;}}this.conEnd = this.config; // config赋值完成}}}},mounted() {// 是否有权限观看完整视频, true: 能 , false: 禁止拖拽; 限制 10%;this.config.disableProgress = !this.modOpenTrial;//如果禁止拖动,后台设置的false,前端设置值得是true.如果允许拖动,后台设置的true,前端设置值得是false.this.config.allowSeekPlayed = !this.modDrag;// #ifdef APP-PLUS// 监听事件 当设备的方向发生变化时触发的事件plus.globalEvent.addEventListener('orientationchange', this.handleOrientation);// #endif// #ifndef  APP-PLUSwindow.addEventListener('orientationchange', this.handleOrientation);// #endifthis.init();},watch: {modOpenTrial(val) {// 是否有权限观看完整视频, true: 能 , false: 禁止拖拽; 限制 10%;this.config.disableProgress = !this.val;}}
};
</script><!-- 视图层 -->
<script module="xgPlayerModule" lang="renderjs">import xgPlayer from 'xgplayer';import HlsJsPlayer from 'xgplayer-hls.js';export default {data(){return {player: null,renderIosTimes: null,renderModOpenTrial: null}},mounted() {},beforeDestroy() {this.player && typeof this.player.destroy === 'function' && this.player.destroy();},methods: {playOrPauseVideoRenderjs() { // 控制视频播放和暂停console.log('暂停视频 或者 播放', this.playOrPauseStatus);if (this.player) {if (this.playOrPauseStatus === 'play') {this.player.play();} else {this.player.pause();}}},changeTimes() {this.renderIosTimes = this.iosTimes},changeModOpenTrial() {this.renderModOpenTrial = this.modOpenTrial},initVideo(newVal,old,ownerInstance,instance) {let that = thisif (that.conEnd && that.conEnd.id && that.conEnd.url && !that.player) {console.log('视图层的initVideo方法========');if (that.player) {that.player.destroy();}if (that.conEnd.url.indexOf('m3u8') !== -1) {that.player = new HlsJsPlayer(that.conEnd);} else { // 不是m3u8that.player = new xgPlayer(that.conEnd);if (that.renderIosTimes) {if (that.player) {that.player.start(that.conEnd.url);that.player.play();}}}console.log('that.player=======', that.player);// 播放that.player.on('play', function () {// 调用逻辑层方法that.$ownerInstance.callMethod('playerMethods')})// 暂停that.player.on('pause', function () {// 调用逻辑层方法that.$ownerInstance.callMethod('playerPauseMethods')})// 播放中that.player.on('timeupdate', function(resPlayer) {// 是否有权限观看完整视频, true: 能 , false: 禁止拖拽; 限制 10%;if (!that.renderModOpenTrial && (resPlayer.currentTime / resPlayer.duration) >= 0.1) {resPlayer.pause();// resPlayer.currentTime = 0;that.$ownerInstance.callMethod('openTrialMe')}// 调用逻辑层方法that.$ownerInstance.callMethod('playTimeUpdate', resPlayer.currentTime)});// 进入全屏that.player.on('getRotateFullscreen', function(value) {if (document.getElementsByClassName('water-turn')[0]) {document.getElementsByClassName('water-turn')[0].style.transform = 'rotate(90deg)';}that.$ownerInstance.callMethod('fullScreenMe')});// 退出全屏that.player.on('exitRotateFullscreen', function(value) {if (document.getElementsByClassName('water-turn')[0]) {document.getElementsByClassName('water-turn')[0].style.transform = 'rotate(0deg)';}that.$ownerInstance.callMethod('exitFullScreenMe')});}}}}
</script>

http://www.ppmy.cn/server/153373.html

相关文章

curl发起带参数的请求

要使用 curl 发起一个带有 application/json 类型参数的请求&#xff0c;你可以使用 -H 选项来设置请求头&#xff0c;并使用 -d 或 --data 选项来传递 JSON 数据。以下是一个示例&#xff1a; 示例&#xff1a;POST 请求 假设你要向 https://example.com/api 发送一个 POST …

分布式系统架构2:服务发现

1.概念 服务发现指的是分布式系统中&#xff0c;服务实例动态注册自己的信息到注册中心&#xff0c;其他服务能发现这些实例的位置&#xff0c;实现服务间通信。 为什么需要服务发现&#xff1f; 对于分布式应用来说&#xff0c;服务发现不是可选项&#xff0c;而是必须的。主要…

C++进阶-1-单继承、多继承、虚继承

C单继承详解 1. 基础概念 继承是面向对象编程中的一个核心概念&#xff0c;允许一个类&#xff08;子类或派生类&#xff09;继承另一个类&#xff08;父类或基类&#xff09;的属性和方法。单继承意味着一个类只能直接继承一个父类。这种简单的结构在许多情况下是足够的&…

【每日学点鸿蒙知识】启动耗时分析、IDE报错、emitter内存泄漏、radio C API、SDK下载失败

1、头条启动场景耗时长&#xff0c;请帮忙分析&#xff1f; 启动慢问题分析如下: 启动慢主要是首帧卡顿了 在 Frame 泳道中&#xff0c;绿色条块代表该帧的渲染过程正常&#xff0c;没有出现卡顿等异常现象&#xff1b;红色或粉红色条块则代表帧的渲染异常&#xff0c;需要重点…

【Spring】BeanFactory与ApplicationContext——ApplicationContext常用实现类

Spring 框架的 IoC&#xff08;控制反转&#xff09;容器为我们提供了灵活且强大的对象管理能力。作为 IoC 容器的核心&#xff0c;ApplicationContext 提供了比 BeanFactory 更加丰富的功能&#xff0c;如国际化支持、事件传播、AOP&#xff08;面向切面编程&#xff09;等。理…

K8S中的PV、PVC介绍和使用

PV-PVC-SC图解 持久卷PV PV概述 persistent volumes持久卷&#xff0c;独立的存储资源&#xff0c;实现K8S持久化存储。可以由外部存储系统&#xff08;如 NFS、GlusterFS、AWS EBS 等&#xff09;支持。PV可以限制资源的大小和容器 访问模式官方介绍ReadWriteOnce (RWO)卷可…

maven的scope详解

Maven 的 scope&#xff08;作用域&#xff09;用于定义依赖项在构建生命周期中的可见性和使用范围。正确设置依赖项的作用域可以帮助优化构建过程&#xff0c;减少不必要的依赖&#xff0c;并确保项目在不同环境中&#xff08;如编译、测试、运行时&#xff09;能够正确工作。…

常用类晨考day15

1.基本数据类型以及对应包装类 Byte Short Integer Long Float Double Boolean Character 2.什么是自动拆箱和装箱&#xff0c;jdk版本有什么要求&#xff1f;代码举 例并标明 Integer a 100; // 装箱 int b a; // 拆箱 从JDK1.5才开始支持 3.NumberFormatException是什么异常…