<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>视频中心</title> <link rel="stylesheet" href="/layui/css/layui.css"> <style> canvas { width: 600px; } </style> </head> <body class="layui-bg-gray"> <div id="header"></div> <div class="layui-row"> <div class="layui-col-xs2"> <div class="grid-demo grid-demo-bg1"> <div class="layui-panel" style="width: auto; margin: 16px;"> <ul class="layui-menu" id="menusss"> <div id="menuView"></div> </ul> </div> </div> </div> <div class="layui-col-xs7"> <div class="grid-demo" id="container" style="margin-top: 16px; width: 100%;"> <video id="videoElement" controls style="width: 100%;"></video> </div> </div> <div class="layui-col-xs2" style="margin-left: 16px; width: 22%; margin-top: 16px;"> <p style="font-size: 4;font-weight: bold; text-align: center;">Super Chat 列表</p> <div class="flow-demo" id="flow" style="height: 60vh; overflow: auto;"></div> </div> </div> <div class="layui-row"> <div class="layui-col-xs2"> </div> <div class="layui-form layui-col-xs1"> <input type="checkbox" id="danmuCheckBox" title="弹幕" lay-skin="tag" lay-filter="danmuCheckBox" on checked> </div> <div class="layui-col-xs4" style="text-align: center;"> <div id="slider" lay-options="{value: 100,input:true}"></div> <span>弹幕透明度</span> </div> <div class="layui-col-xs2" style="text-align: right; align-self: center;"> 弹幕装载数:<span id="danmuSize">你猜</span> </div> </div> <div class="layui-row"> <div class="layui-col-xs2"> </div> <div class="layui-col-xs7" style="width: auto; height: 50%;"> <canvas id="giftChart" style="width: 100%; height: 100%;"></canvas> </div> </div> <div style="margin-bottom: 10vh;"></div> </body> <script id="menulist" type="text/html"> <ul class="layui-tab-title"> {{# layui.each(Object.keys(d), function(index, item){ }} <li class="layui-menu-item-group layui-menu-item-up" lay-options="{type: 'group'}"> <div class="layui-menu-body-title"> {{= item}} <i class="layui-icon layui-icon-up"></i> </div> <ul> {{# layui.each(d[item], function(index, video){ }} <li lay-options="{id: {{= video.path}} }"> <div class="layui-menu-body-title">{{= video.name}}</div> </li> {{# }); }} </ul> </li> {{# }); }} </ul> </script> <script id="superChatCard" type="text/html"> {{# layui.each(d, function(index, item){ }} <li> <div class="layui-bg-gray" style="padding: 16px;"> <div class="layui-row layui-col-space16"> <div class="layui-card" style=" background-color: {{= item.backgroundBottomColor }};"> <div class="layui-card-header" ><img src="#" onerror="showImage('{{= item.userAvatar}}',this)" style="width: 40px; height: 40px;"/><a href="https://space.bilibili.com/{{= item.uid}}" target="_blank"><span style="color: {{= item.userNameColor}};">{{= item.userName}}</span></a> <span style="float: right;">金额:{{= item.price}}¥</span> </div> <div class="layui-card-body"> <p style="color: {{= item.message_font_color}} ;">{{= item.message}}</p> <hr> <p style="color: {{= item.message_font_color}} ;">{{= item.message_trans}}</p> </div> </div> </div> </div> </li> {{# }); }} </script> <script src="/js/jquery-3.2.1.js"></script> <script src="/js/CommonConfig.js"></script> <script src="/js/httpUtils.js"></script> <script src="/layui/layui.js"></script> <script src="/js/hls.js"></script> <script src="/js/fly-barrage.iife.js"></script> <script src="/js/lodash.min.js"></script> <script src="/js/Chart.min.js"></script> <script> headerModel = 2; $('#header').load("/html/header.html"); // 获取弹幕渲染器 class const { BarrageRenderer } = FlyBarrage; // 获取 video 元素引用 const video = document.getElementById('videoElement'); var barrageRenderer; var danmuConfig = {} video.volume = 0.1; function initBarrageRenderer() { const barrages = []; danmuConfig = { heightReduce: 60, speed: 100, fontWeight: 'bold', } barrageRenderer = new BarrageRenderer({ container: 'container', video: video, barrages, renderConfig: danmuConfig, }); // 给 video 元素绑定 play 事件,回调函数内部调用渲染器实例的 play 方法 video.addEventListener('play', () => { barrageRenderer.play(); }); // 给 video 元素绑定 pause 事件,回调函数内部调用渲染器实例的 pause 方法 video.addEventListener('pause', () => { barrageRenderer.pause(); }); video.addEventListener('timeupdate', function () { // 当前播放时间(秒) const currentTime = this.currentTime; // 视频总时长(秒) const duration = this.duration; // 计算播放进度百分比 const progressPercentage = (currentTime / duration) * 100; if (currentTime % 10 === 0) { console.log("到10秒") } }); // container 尺寸发生了变化的话,需要调用渲染器实例的 resize 方法 // 这里需要借助 lodash 的防抖函数封装一下,不要太过频繁的调用 resize window.onresize = _.debounce(() => { barrageRenderer.resize(); }, 150); } $('#danmuCheckBox').get(0).addEventListener('input', function () { if (this.checked) { console.log('复选框被选中'); } else { console.log('复选框未被选中'); } }) </script> <script> var roomId = getParam('roomId'); var videoId; layui.use(function () { var flow = layui.flow; var dropdown = layui.dropdown; var layer = layui.layer; var laytpl = layui.laytpl; var slider = layui.slider; var form = layui.form; var sliderValue = 100; // 单个渲染 slider.render({ elem: '#slider', change: function (value) { if (barrageRenderer === null || barrageRenderer === undefined) return; danmuConfig['opacity'] = value / 100 sliderValue = value; barrageRenderer.setRenderConfig(danmuConfig) } }); form.on('checkbox(danmuCheckBox)', function (data) { var checked = data.elem.checked; // 获得 checkbox 选中状态 if (barrageRenderer === null || barrageRenderer === undefined) return; if (checked) { danmuConfig['opacity'] = sliderValue / 100 } else { danmuConfig['opacity'] = 0 } barrageRenderer.setRenderConfig(danmuConfig) }); function initTabs() { getVideo(roomId, 0, 0) .then(data => { initMenu(data.data.children) }) } dropdown.on('click(menusss)', function (options) { // playVideo() videoId = options.id; getPlayerVideo(roomId, options.id) .then(data => { console.log(data) setTimeout(function () { playVideo(data.data) }, 1000) }); initChart(roomId, options.id) }); var chartView = null; function initChart(roomId, videoId) { getVideoGiftInfo(roomId, videoId) .then(data => { if (data.status != 100) { return } var lables = []; var values = []; data.data.guardInfo.forEach(item => { lables.push(item.gift_name + "\n" + item.total_price / 100 + "¥") values.push(item.total_num) }); data.data.giftInfo.forEach(item => { lables.push(item.gift_name + "\n" + item.total_price / 100 + "¥") values.push(item.total_gift_num) }); if(chartView!==null){ chartView.destroy() } chartView = new Chart($('#giftChart').get(0), { type: 'pie', data: { labels: lables, datasets: [{ label: '礼物(总额:' + data.data.price / 100 + "¥)", data: values, borderWidth: 1 } ] }, options: { scales: { y: { beginAtZero: true } } } }); }) } function initMenu(data) { var view = $("#menuView").get(0); laytpl($('#menulist').get(0).innerHTML).render(data, function (html) { view.innerHTML = html; }); } function init() { if (!hasString(getParam('roomId'))) { showAnchor(); return } initTabs() initBarrageRenderer(); } function showAnchor() { layer.open({ type: 2, // page 层类型 area: ['320px', '400px'], title: '选择主播', shade: 0.6, // 遮罩透明度 shadeClose: false, // 点击遮罩区域,关闭弹层 maxmin: true, // 允许全屏最小化 anim: 1, // 0-6 的动画形式,-1 不开启 btn: ['确定', '取消'], content: '/html/ui/selectAnchor.html', yes: function (index, layero) { var iframeWin = window[layero.find('iframe')[0]['name']]; var anchorRoomId = iframeWin.$('#anchorRoomId')[0].value; if (!hasString(anchorRoomId)) { layer.msg("请选择") return } let url = new URL(window.location.href); url.searchParams.set('roomId', anchorRoomId); window.location.href = url.toString(); } }); } function playVideo(url) { var video = document.getElementById('videoElement'); var videoSrc = window.location.origin + url; console.log('url = ' + videoSrc) var hls = new Hls(); hls.loadSource(videoSrc); hls.attachMedia(video); initDanmu() video.addEventListener('loadedmetadata', function () { // 设置视频的初始播放时间 video.currentTime = 0; }) } function initDanmu() { barrageRenderer.setBarrages([]) getDanmu(getParam('roomId'), videoId) .then(data => { barrageRenderer.setBarrages(data.data.danmu); $('#danmuSize').get(0).innerHTML = data.data.danmu.length initSC(data.data.superChat) }) } function initSC(scList) { flow.load({ elem: '#flow', // 流加载容器 scrollElem: '#flow', // 滚动条所在元素,一般不用填,此处只是演示需要。 isAuto: true, isLazyimg: false, done: function (page, next) { // 加载下一页 // 模拟插入 console.log(scList) laytpl($('#superChatCard').get(0).innerHTML).render(scList, function (html) { console.log(html) next(html, false) }); } }); } init() }) </script> <style> </style> </html>