傲渊山岳 发表于 2024-12-26 05:15:53

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

配景:在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: ,
                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.autoplay
                  this.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; // 预加载时间15s
                        this.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
      // #ifndefAPP-PLUS
      window.addEventListener('orientationchange', this.handleOrientation);
      // #endif
      this.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 = this
                if (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 { // 不是m3u8
                        that.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')) {
                            document.getElementsByClassName('water-turn').style.transform = 'rotate(90deg)';
                        }
                        that.$ownerInstance.callMethod('fullScreenMe')
                  });
                  // 退出全屏
                  that.player.on('exitRotateFullscreen', function(value) {
                        if (document.getElementsByClassName('water-turn')) {
                            document.getElementsByClassName('water-turn').style.transform = 'rotate(0deg)';
                        }
                        that.$ownerInstance.callMethod('exitFullScreenMe')
                  });
                }
            }
                }
        }
</script>


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: uniapp 基于xgplayer(西瓜视频) + renderjs开辟,实现APP视频播放