uniapp中使用xgplayer直播、讨论区的简单实现、第三方复制功能
使用的场景:欲做一个直播间,并且拉流地址支持 .flv、.m3u8、mp4。同时播放控件需要自定义,支持直播回放、直播时移、微窗显示。
其次,捎带记录一下讨论区功能。
期间使用了 video-player (.flv 格式的直播暂时不支持播放)
aliplayer (这个忘记是什么原因了总之也没用成)
xgplayer(本次介绍就是使用的这个组件)
主动献上他的官网地址: https://v2.h5player.bytedance.com/api/
一、安装
1 2 | # 最新稳定版 $ npm install xgplayer |
二、使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | import 'xgplayer' ; import FlvPlayer from 'xgplayer-flv' ; import HlsPlayer from 'xgplayer-hls.js' ; import Mp4Player from 'xgplayer-mp4' ; // 下面引入的插件需要的引入不需要也可以不引入 import Player from 'xgplayer/dist/core_player' ; import play from 'xgplayer/dist/controls/play' ; import fullscreen from 'xgplayer/dist/controls/fullscreen' ; import progress from 'xgplayer/dist/controls/progress' ; import volume from 'xgplayer/dist/controls/volume' ; import pip from 'xgplayer/dist/controls/pip' ; import flex from 'xgplayer/dist/controls/flex' ; /* * 这里注意 别再created里面实例化 最好是在mounted里面实例化 */ mounted() { // 三种格式使用 // 1、 this .player = new FlvPlayer({ id: 'videoPlayer' , url: this .roomAddress, poster: this .roomAddress.replaceAll( '.flv' , '.png' ), isLive: true , preloadTime: 30, minCachedTime: 5, cors: true , // fluid: true,//设置为流式布局,可使播放器宽度跟随父元素的宽度大小变化 autoplayMuted: true , controlPlugins: [ flex ], }) // 2、 this .player = new HlsPlayer({ id: 'videoPlayer' , // url: this.roomAddress.replaceAll('app.livestream.bksti.com', '192.168.2.100:12002'), url: this .roomAddress, poster: this .roomAddress.replaceAll( '.m3u8' , '.png' ), controlPlugins: [ flex ], // fluid: true,//设置为流式布局,可使播放器宽度跟随父元素的宽度大小变化 autoplayMuted: true , useHls: true }) // 3、 this .player = new Mp4Player({ id: 'videoPlayer' , url: roomPlayback, playNext: function (){ if (videoArr.length > 0) { return { urlList: videoArr } } }(), // fluid: true,//设置为流式布局,可使播放器宽度跟随父元素的宽度大小变化 autoplayMuted: true , loop: true , //是否循环播放 volume: 1, controlPlugins: [ flex ], autoplay: true , maxBufferLength: 20 // 设置最大缓冲区时长,默认5秒 }) //以下举例示例里面的属性,需要哪个就用哪个。 //el: document.getElementById('mse'), id: 'videoPlayer' , //height:300, url: 'http://211.943/268769823.mp4' , // fluid: true,//设置为流式布局,可使播放器宽度跟随父元素的宽度大小变化 //volume: 0.6,//开发者可以为播放器预设音量大小 参考值0~1 autoplay: false , //是否自动播放, muted: true , autoplayMuted: true , loop: true , //是否循环播放 poster: '../assets/move2.png' , playbackRate: [0.5, 0.75, 1, 1.5, 2], defaultPlaybackRate: 1, lastPlayTime: 70, //视频起播时间(单位:秒) lastPlayTimeHideDelay: 3, //提示文字展示时长(单位:秒) rotate: { //视频旋转按钮配置项 innerRotate: true , //只旋转内部video clockwise: false // 旋转方向是否为顺时针 }, playNext: { urlList: [ 'http://211.88//8898.MP4' , 'http://211.88//8898.MP' , 'http://211.88//8898.MP4' ], }, download: true , //设置download控件显示 danmu: { comments: [ //弹幕数组 { duration: 15000, //弹幕持续显示时间,毫秒(最低为5000毫秒) id: '1' , //弹幕id,需唯一 start: 3000, //弹幕出现时间,毫秒 prior: true , //该条弹幕优先显示,默认false color: true , //该条弹幕为彩色弹幕,默认false txt: '长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕' , //弹幕文字内容 style: { //弹幕自定义样式 color: '#ff9500' , fontSize: '20px' , border: 'solid 1px #ff9500' , borderRadius: '50px' , padding: '5px 11px' , backgroundColor: 'rgba(255, 255, 255, 0.1)' }, mode: 'top' , //显示模式,top顶部居中,bottom底部居中,scroll滚动,默认为scroll } ], panel: true , //弹幕面板 area: { //弹幕显示区域 start: 0, //区域顶部到播放器顶部所占播放器高度的比例 end: 1 //区域底部到播放器顶部所占播放器高度的比例 }, closeDefaultBtn: false , //开启此项后不使用默认提供的弹幕开关,默认使用西瓜播放器提供的开关 defaultOff: false //开启此项后弹幕不会初始化,默认初始化弹幕 }, // 标记点所对应的播放时间 progressDot: [ { time: 2000, //展示标记的时间 text: '他死了' , //鼠标hover在标记时展示的文字 // duration: 8, //标记段长度(以时长计算) style: { //标记样式 background: 'red' } }, { time: 1500, text: '他才是凶手?' }, { time: 2600, text: '又是谁杀了她?' , // duration: 8, }, { time: 3800, text: '怎么回事?' , // duration: 8, } ] } // 如果需要切换下一个视频需要做一下操作 this .player = new Mp4Player({ id: 'videoPlayer' , url: roomPlayback, playNext: function (){ if (videoArr.length > 0) { return { urlList: videoArr } } }(), volume: 1, controlPlugins: [ flex ], autoplay: true , maxBufferLength: 20 // 设置最大缓冲区时长,默认5秒 }) this .player.on( 'ended' , () =>{ console.log( '播放结束,即将播放下一个' ) this .player.emit( 'playNextBtnClick' ) }) // player.emit('playNextBtnClick') 这个在源码里可以找到<br><br>//配置<br>// 1、去掉播放视频中的loading 在ignores中配置loading |
简单说下讨论区的实现 ,这里也是使用第三方的 。websocket已经被封装好的包括心跳、重连之类的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import SockJS from 'sockjs-client' ; import EventBus from '@vertx/eventbus-bridge-client.js' data() { return { assetsUrl: assetsUrl, ws: new EventBus(liveWs + '/im/message/send' , { vertxbus_reconnect_attempts_max: Infinity, // Max reconnect attempts vertxbus_reconnect_delay_min: 1000, // Initial delay (in ms) before first reconnect attempt vertxbus_reconnect_delay_max: 5000, // Max delay (in ms) between reconnect attempts vertxbus_reconnect_exponent: 2, // Exponential backoff factor vertxbus_randomization_factor: 0.5 // Randomization factor between 0 and 1 }), } } created() { this .ws.enableReconnect( true ); this .ws.onerror = err => {} }, mounted() { this .ws.onopen = () => { this .ws.registerHandler( '12345:message:' + this .roomData.roomId, (error, message) => { // 收到聊天室消息 console.log( 'received a appid:message: ' , message.body); this .commentList.push({ type: message.body.type, user: '观众' , content: message.body.text, userName: message.body.userName, userId: message.body.userId, }) this .$nextTick(() => { // console.log(this.$refs) this .$refs.comment.$el.scrollTop = this .$refs.comment.$el.scrollHeight }) }); } }<br><br><br><br><br><br><br> |
捎带在附加一个第三方复制插件 Clipboard
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 主要用到的是 class="share" @click.native.prevent="copy('.share')" :data-clipboard-text="" <image src= "/static/icon-fenxiang.png" mode= "" class = "share" @click.native.prevent= "copy('.share')" :data-clipboard-text= "roomData.roomAddress" ></image> // 复制 copy(name) { let clipboard = new Clipboard(name); //单页面引用 clipboard.on( "success" , (e) => { // 释放内存 clipboard.destroy(); this .$cnt.okmsg( "复制成功!" ) }); clipboard.on( "error" , (e) => { // 不支持复制 this .$cnt.errmsg( "复制失败!" ) // 释放内存 clipboard.destroy(); }); }, |
加一个阴影部分:
1 2 3 4 5 6 7 8 | className{ background: linear-gradient(180deg, #fff,hsla(0,0%,100%,0)); height: 44px; position: absolute; top: 0; width: 100%; z-index: 1; } |
努力到无能为力,拼搏到感动自己。
欢迎大家在下方多多评论。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通