You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:19:51