如何解决DOMContentLoaded或addEventListener导致的视频Canvas空白问题?
问题描述
页面初始加载时,canvas有时会因<video>标签的display:none属性显示空白,视频无法正常启动。该现象并非必现:Firefox中出现概率较低,Chrome中则频繁出现。若出现空白,点击canvas区域后会显示introstill.png封面图,随后可正常启动视频。
推测问题可能与脚本末尾myvideo.init的函数结构有关,可能破坏了addEventListener的正常执行,但不确定具体原因。
该问题在本地localhost的.html文件及线上服务器环境中均会出现。已尝试以下解决方案,但均无效果:
- 使用
jQuery('document').ready(function()包裹整个函数; - 在主机端禁用MP4缓存。
浏览器控制台无报错信息,也不存在插件冲突问题。
根据@titus的评论,想了解该如何修改document.addEventListener('DOMContentLoaded', () => {这部分代码?
另外,自身JavaScript知识有限,无法剔除无关代码来制作关于addEventListener或DOMContentLoaded的最小复现示例。
相关代码
<script> var myvideo = (function (window) { var app = {}; var buttonBg_out = new Image(); var buttonBg_over = new Image(); var nextText = new Image(); var beginText = new Image(); var startAgain = new Image(); var introStill = new Image(); var pauseOverlay = new Image(); var REAL_WIDTH = 656; var REAL_HEIGHT = 386; var ASPECT_RATIO = REAL_WIDTH / REAL_HEIGHT; var SCALE = 1.0; app.init = function (root) { buttonBg_out.src = root + 'button-out.png'; buttonBg_over.src = root + 'button-over.png'; nextText.src = root + 'next.png'; beginText.src = root + 'begin.png'; startAgain.src = root + 'startagain.png'; introStill.src = root + 'introstill.png'; pauseOverlay.src = root + 'pauseoverlay.png'; var document = window.document; document.addEventListener('DOMContentLoaded', () => { // addEventListener var video = document.getElementById('myvid'); var canvas = document.getElementById('playbackcontainer'); var ctx = canvas.getContext('2d'); introStill.onload = () => { ctx.drawImage(introStill,0,31,introStill.width,introStill.height); }; var rescaling = function () { SCALE = canvas.clientWidth / REAL_WIDTH; setTimeout(rescaling, 10); }; rescaling(); var drawVideo = function () { if (video.paused || video.ended) return; ctx.drawImage(video,0,0,canvas.width,canvas.height); drawButton(); setTimeout(drawVideo,1); // might fiddle with this timeout; }; var button = {x:0,y:0, w:127, h:66, state: buttonBg_out, text: beginText, visible: false }; var localXY = function (e) { var rect = canvas.getBoundingClientRect(); var x = e.clientX - rect.left; var y = e.clientY - rect.top; return {x:x,y:y}; }; var isOverButton = function (e) { var xy = localXY(e); var x = xy.x; var y = xy.y; return (x >= (button.x * SCALE) && y >= (button.y * SCALE) && x <= ((button.x + button.w)*SCALE) && y <= ((button.y + button.h)*SCALE)); }; var drawButton = function () { if (button.visible) { ctx.drawImage(button.state, button.x ,button.y , button.w ,button.h ); ctx.drawImage(button.text, (button.x + 14) , (button.y + 23) , button.text.width , button.text.height ); } }; var isOverStartOver = function (e) { var xy = localXY(e); return xy.x >= 9*SCALE && xy.x <= 92*SCALE && xy.y >= 367*SCALE && xy.y <= 379*SCALE; }; var isOverReplayScene = function (e) { var xy = localXY(e); return xy.x >= 102*SCALE && xy.x <= 186*SCALE && xy.y >= 367*SCALE && xy.y <= 379*SCALE; }; var permissionGiven = false; var currentScene = 0; var sceneBounds = [{start:4.583, showButton:13.849, loopStart:15.116, loopEnd:22.183, afterPress:23.416}, {start:25.649, showButton:53.416, afterPress: 55.983}, {start:58.216, showButton:99.0, afterPress:100.483}, {start:103.649, showButton:156.149, afterPress:156.816}, {start:159.049, showButton:229.883, loopStart:230.5, loopEnd:236.383, afterPress:242.00}]; video.addEventListener('play', drawVideo, false); video.addEventListener('timeupdate', () => { var bounds = sceneBounds[currentScene]; if (video.currentTime >= bounds.showButton) { button.visible = true; drawButton(); } if (bounds.loopEnd != null) { // keep playing if (video.currentTime >= bounds.loopEnd) { video.currentTime = bounds.loopStart; } } else if (video.currentTime >= bounds.showButton) { // pause video.pause(); } }); canvas.addEventListener('mousemove', (e) => { if (isOverButton(e)) { button.state=buttonBg_over; drawButton(); } else { button.state=buttonBg_out; drawButton(); } }); canvas.addEventListener('mousedown', (e) => { if (!permissionGiven) { permissionGiven = true; video.currentTime = sceneBounds[0].start; video.play(); button.x = 322; button.y = 244; } else { if (video.paused && currentScene > 0 && currentScene < 4 && !isOverButton(e)) { if (isOverStartOver(e)) { video.currentTime = sceneBounds[0].start; button.visible = false; button.x = 322; button.y = 244; button.text = beginText; currentScene = 0; video.play(); } else if (isOverReplayScene(e)) { button.visible = false; video.currentTime = sceneBounds[currentScene].start; video.play(); } else { video.play(); } } else if (currentScene == 4 && !isOverButton(e)) { if (isOverStartOver(e)) { button.visible = false; video.currentTime = sceneBounds[currentScene].start; video.play(); } } else if (button.visible && isOverButton(e)) { // button was presssed currentScene = (currentScene + 1) % sceneBounds.length; if (currentScene == 0) { button.text = beginText; video.currentTime = sceneBounds[currentScene].start; button.x = 322; button.y = 244; } else { button.text = nextText; button.x = 515; button.y = 304; video.currentTime = sceneBounds[currentScene-1].afterPress; } if (currentScene == 4) button.text = startAgain; button.visible = false; video.play(); } else if (video.paused) { video.play(); } else { video.pause(); ctx.drawImage(pauseOverlay,0,0,canvas.width,canvas.height); } } }); }); }; return app; })(window); (function(){ var thevid = document.getElementById("myvid"); myvideo.init("/path/to/folder/with/images/and/mp4/"); })(); </script> <div class="flex-video"> <video id="myvid" style="display:none;" playsinline> <source src="/path/to/folder/with/images/and/mp4/the_video.mp4" type="video/mp4"/></video> <canvas id="playbackcontainer" width="656" height="386"></canvas> </div>
内容的提问来源于stack exchange,提问作者user5853892
相关产品推荐
相关产品推荐

