Laravel项目加密视频在Video.js播放时addEventListener及广告插件报错
解决Video.js + IMA广告初始化时机错误及事件监听失效问题
问题分析
- 初始化时机错误:你添加的
data-setup='{}'会触发Video.js自动初始化播放器,而你又在DOMContentLoaded回调里手动调用videojs(video.id),导致播放器重复初始化。IMA广告依赖的videojs-contrib-ads要求在播放器初始化后的同一事件循环内加载,自动初始化提前触发了loadstart事件,后续手动加载插件就会错过时机,触发报错。 - 事件监听失效:Video.js会封装原生video元素,直接给原生video绑定
addEventListener可能被播放器的事件系统拦截,导致无法触发,应该使用Video.js播放器实例的事件绑定方法。
解决方案
1. 移除自动初始化属性
删除video标签中的data-setup='{}',完全由代码手动初始化播放器,确保流程可控。
修改后的视图代码:
<video class="img-fluid myVideo video-js vjs-default-skin" id="content_video{{ $video_list->id }}" preload="none" controls data-video-id="{{ Crypt::encrypt($video_list->id) }}"> @if (Auth::check()) <source src="{{ route('video.player.show', ['filename' => $video_list->unique_number.'.m3u8','type' => 'full','video_id' => $video_list->unique_number]) }}" type="application/x-mpegURL" class="full-video"> @endif </video>
2. 调整JS代码,确保插件及时初始化并使用Video.js事件系统
- 替换原生video元素的事件监听为
player.on()绑定 - 确保IMA插件在播放器实例创建后立即初始化
- 修正options中的id为当前视频的实际id
修改后的JS代码:
<script> document.addEventListener('DOMContentLoaded', function() { console.log('afterload'); const videos = document.querySelectorAll('.myVideo'); let playing = []; videos.forEach((video, index) => { console.log('video'); console.log(video.id); const overlay = document.querySelectorAll('.overlay')[index]; const paymentoverlay = document.querySelectorAll('.paymentoverlay')[index]; // 手动初始化播放器,完全控制初始化流程 const player = videojs(video.id); // 修正options中的id为当前视频的实际id var options = { id: video.id, adTagUrl: 'http://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=xml_vmap1&unviewed_position_start=1&cust_params=sample_ar%3Dpremidpostpod%26deployment%3Dgmf-js&cmsid=496&vid=short_onecue&correlator=' }; // 创建播放器后立即初始化IMA插件,确保在同一事件循环内完成 player.ima(options); // 使用Video.js播放器实例绑定ended事件 player.on('ended', function() { console.log('111'); handleVideoConditions(video, overlay, paymentoverlay); }); // 使用Video.js的play事件,替代原生onplay player.on('play', function() { playing.push(video); if (!player.paused()) { player.controls(true); registerView(video); } }); }); function handleVideoConditions(video, overlay, paymentoverlay) { console.log('222'); const isShortVideo = video.querySelector('.short-video'); const isFullVideo = video.querySelector('.full-video'); if (!isUserLoggedIn && isShortVideo) { overlay.style.display = 'block'; } else if (isUserLoggedIn && isShortVideo) { paymentoverlay.style.display = 'block'; } } async function registerView(video) { const videoId = video.getAttribute('data-video-id'); const response = await fetch(`{{ route('video.registerView', ['videoId' => ':videoId']) }}` .replace(':videoId', videoId)); const data = await response.json(); $('#videoview' + data.id).html(data.view_count); } }); </script>
额外说明
- 手动初始化后,所有视频相关事件都要通过Video.js的
player.on()绑定,确保事件被正确捕获,避免原生事件被封装层拦截。 - 移除
data-setup后,播放器初始化完全由代码控制,从根源上解决了videojs-contrib-ads初始化时机过晚的问题,插件在播放器创建后的同一代码块内立即初始化,符合要求的"同一事件循环"条件。
内容的提问来源于stack exchange,提问作者vinod
相关产品推荐
相关产品推荐

