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

news/2024/12/27 5:22:00/

背景:在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/news/1558443.html

相关文章

【YOLO】(基础篇一)YOLO介绍

YOLO YOLO&#xff08;You Only Look Once&#xff09;是一种用于实时物体检测的算法&#xff0c;由Joseph Redmon等人提出。它能够同时进行物体分类和定位&#xff0c;并且因其速度和效率而广受赞誉。 工作原理 假设我们要对这张猫的图片完成目标检测&#xff0c;需要框选出…

DinoGrid是开放版圣诞礼物(NFT)

「DinoGrid」 是一个受 CC0 社区项目 Tiny Dinos 启发的 NFT 项目。它创新性地融合了三大数学概念&#xff1a;简单完美正方形、阶乘全排列和四色定理。每件艺术品都是独一无二的生成创作&#xff0c;展现了几何精确性、算法美感和动态配色的和谐统一。通过用创新算法重新诠释 …

【AI大模型】探索GPT模型的奥秘:引领自然语言处理的新纪元

目录 &#x1f354; GPT介绍 &#x1f354; GPT的架构 &#x1f354; GPT训练过程 3.1 无监督的预训练语言模型 3.2 有监督的下游任务fine-tunning &#x1f354; 小结 学习目标 了解什么是GPT.掌握GPT的架构.掌握GPT的预训练任务. &#x1f354; GPT介绍 GPT是OpenAI公…

【每日学点鸿蒙知识】getStringSync性能、avplayer、Socket、ScanKit、Authentication

1、HarmonyOS getStringSync和getNumber方法耗时导致性能问题&#xff1f; 页面中有很多场景需要使用getContext().resourceManager.getStringSync()方法&#xff0c;将resource资源取出&#xff0c;在其他地方使用&#xff1b;但是&#xff0c;经分析&#xff0c;getStringSy…

Java爬虫获取1688 item_search_img接口详细解析

概述 1688作为中国领先的B2B电商平台&#xff0c;提供了丰富的API接口供开发者获取商品信息。item_search_img接口允许通过图片搜索商品&#xff0c;这对于需要基于图片进行商品查找的应用场景非常有用。本文将详细介绍如何使用Java爬虫技术获取1688的item_search_img接口数据…

短视频运营行业该如何选择服务器?

在互联网快速发展的时代&#xff0c;短视频行业也应运而生&#xff0c;企业为了保证用户能够浏览流畅且稳定的短视频&#xff0c;则需要选择一台合适的服务器来运行相关业务&#xff0c;本文就来探讨一下短视频运营行业该如何选择服务器吧&#xff01; 短视频行业一般需要处理大…

RabbitMQ中的普通Confirm模式:深入解析与最佳实践

在分布式系统中&#xff0c;消息队列&#xff08;Message Queue&#xff09;是实现异步通信和解耦的重要组件。RabbitMQ作为一种广泛使用的消息中间件&#xff0c;提供了多种消息确认机制&#xff08;Confirm Mode&#xff09;&#xff0c;以确保消息的可靠传递。本文将深入探讨…

帝国cms同一条信息使用不同的多个内容页模板伪静态实现教程

理论上可以实现一条信息使用无数个内容页模板&#xff0c;实现过程&#xff1a; 1、/e/action目录下新建bishun.php&#xff0c;内容如下&#xff1a; <?php require(../class/connect.php); require(../class/db_sql.php); require(../class/functions.php); require(..…