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

调用video.play()时网页视频白屏无声音问题求助

问题描述

我希望在网站上播放视频文件,编写了如下JavaScript函数:

function closePageWithCountdown(seconds) {
  const countdownElement = document.createElement("countdowntime");
  countdownElement.style.position = "fixed";
  countdownElement.style.top = "0";
  countdownElement.style.left = "0";
  countdownElement.style.backgroundColor = "red";
  countdownElement.style.color = "white";
  countdownElement.style.padding = "5px";

  document.body.appendChild(countdownElement);

  function updateCountdown() {
    countdownElement.textContent = `Page will automatically close in ${seconds} seconds`;

    if (seconds === 0) {
      document.body.removeChild(countdownElement);
      document.getElementsByTagName('html')[0].remove();
      document.write('Resource Exhausted !\n<br>You may reload the page or close the tab.');
      var centeredText = document.createElement("div");
      centeredText.innerHTML = "Some Text Here";
      centeredText.style.position = "fixed";
      centeredText.style.bottom = "0";
      centeredText.style.left = "0";
      centeredText.style.right = "0";
      centeredText.style.textAlign = "center";
      // centeredText.style.backgroundColor = "rgba(255, 255, 255, 0.8";
      centeredText.style.padding = "10px";
      centeredText.style.zIndex = "999"; // Ensures it appears on top of other content
      
      // Append the element to the body
      document.body.appendChild(centeredText);

      document.getElementsByTagName('html')[0].style.overflow = 'hidden';
      document.getElementsByTagName('body')[0].style.overflow = 'hidden';
      
      var colors = ['red', 'blue', 'green']; // List of rainbow colors
      var colorIndex = 0; // Initialize color index

      function flash() {
            centeredText.style.color = colors[colorIndex];
            colorIndex = (colorIndex + 1) % colors.length; // Cycle through colors
      }

      var clr = setInterval(flash, 500);
      
      // Create a new div element to hold the text
      var flashbackText = document.createElement('div');
      flashbackText.innerHTML = 'Click here to watch';
      flashbackText.style.position = 'absolute';
      flashbackText.style.top = '50%';
      flashbackText.style.left = '50%';
      flashbackText.style.transform = 'translate(-50%, -50%)';
      flashbackText.style.fontSize = '1.5em';
      flashbackText.style.fontWeight = 'bold';
      flashbackText.style.backgroundColor = 'yellow';
      flashbackText.style.padding = '10px';
      flashbackText.style.cursor = 'pointer';
      flashbackText.style.zIndex = '1000'; // Ensure it's above other elements

      // Append the text to the body
      document.body.appendChild(flashbackText);
    
      // Event listener for the click event
      flashbackText.addEventListener('click', function() {
       // Clear the screen
       document.body.innerHTML = '';

       // Create a video element
       var video = document.createElement('video');
       video.id = 'myVideo';
       video.style.position = 'absolute';
       video.style.top = '50%';
       video.style.left = '50%';
       video.style.transform = 'translate(-50%, -50%) rotate(90deg)'; // Rotate the video 90 degrees
       video.style.width = '100vh'; // Use viewport height as width for landscape
       video.style.height = '100vw'; // Use viewport width as height for landscape
       video.style.objectFit = 'contain'; // Ensure it covers the full area
       video.autoplay = true;
       video.controls = false; // Hide controls

       // Set the source of the video
       var source = document.createElement('source');
       source.src = './myvideo.mp4'; // Replace with the path to your video
       source.type = 'video/mp4';

       // Append source to video element
       video.appendChild(source);

       // Add the video to the screen
       document.body.appendChild(video);

       video.onloadedmetadata = function() {
         console.log('Video metadata loaded successfully');
         console.log('Video duration:', video.duration);
       }; 
       video.onerror = function() {
        console.error('Error loading the video');
       };      
        
       // Play the video
       video.play();

       // Event listener for when the video ends
       video.addEventListener('ended', function() {
        // Clear the video and show the original text again
        document.body.innerHTML = '';
        document.body.appendChild(flashbackText);
        document.body.appendChild(centeredText);
        document.write('Resource Exhausted !\n<br>You may reload the page or close the tab.');
       });    
      });
           

    } else {
      seconds--;
      setTimeout(updateCountdown, 1000);
    }
  }

  updateCountdown();
}
closePageWithCountdown(1) // 1 sec for testing

预期行为:点击屏幕中央的高亮文本即可播放视频,视频结束后返回原页面内容。

实际问题:运行时页面显示白屏且无声音,video.onloadedmetadata和video.onerror的控制台日志均未触发。同时疑问:是否因为未在index.html中添加<video>标签?另外使用telegra.ph视频链接作为source.src时偶尔可以正常运行。


问题分析与解决方案

核心问题梳理

  1. 错误移除<html>元素:代码中document.getElementsByTagName('html')[0].remove();直接销毁了整个文档根节点,后续document.write虽会重建文档,但会导致DOM上下文混乱,后续元素的事件绑定、加载逻辑全部失效。
  2. 滥用document.write:页面加载完成后调用document.write会清空当前文档,覆盖之前添加的元素;视频结束后再次调用会直接抹掉刚恢复的flashbackText和centeredText。
  3. 视频播放上下文异常:DOM结构被反复破坏重建后,视频元素的加载上下文失效,导致onloadedmetadata和onerror无法触发。
  4. 无需提前添加<video>标签:动态创建<video>元素完全合法,问题不在此。

修改后的代码

function closePageWithCountdown(seconds) {
  const countdownElement = document.createElement("div");
  countdownElement.style.position = "fixed";
  countdownElement.style.top = "0";
  countdownElement.style.left = "0";
  countdownElement.style.backgroundColor = "red";
  countdownElement.style.color = "white";
  countdownElement.style.padding = "5px";

  document.body.appendChild(countdownElement);

  function updateCountdown() {
    countdownElement.textContent = `Page will automatically close in ${seconds} seconds`;

    if (seconds === 0) {
      document.body.removeChild(countdownElement);
      // 替换移除html元素的操作,直接清空body并添加提示内容
      document.body.innerHTML = '<div id="exhaustedTip">Resource Exhausted !<br>You may reload the page or close the tab.</div>';
      
      const exhaustedTip = document.getElementById('exhaustedTip');
      exhaustedTip.style.margin = '20px';

      const centeredText = document.createElement("div");
      centeredText.innerHTML = "Some Text Here";
      centeredText.style.position = "fixed";
      centeredText.style.bottom = "0";
      centeredText.style.left = "0";
      centeredText.style.right = "0";
      centeredText.style.textAlign = "center";
      centeredText.style.padding = "10px";
      centeredText.style.zIndex = "999";

      document.body.appendChild(centeredText);

      document.documentElement.style.overflow = 'hidden';
      document.body.style.overflow = 'hidden';
      
      const colors = ['red', 'blue', 'green'];
      let colorIndex = 0;

      const flash = () => {
        centeredText.style.color = colors[colorIndex];
        colorIndex = (colorIndex + 1) % colors.length;
      };

      let clr = setInterval(flash, 500);
      
      const flashbackText = document.createElement('div');
      flashbackText.innerHTML = 'Click here to watch';
      flashbackText.style.position = 'absolute';
      flashbackText.style.top = '50%';
      flashbackText.style.left = '50%';
      flashbackText.style.transform = 'translate(-50%, -50%)';
      flashbackText.style.fontSize = '1.5em';
      flashbackText.style.fontWeight = 'bold';
      flashbackText.style.backgroundColor = 'yellow';
      flashbackText.style.padding = '10px';
      flashbackText.style.cursor = 'pointer';
      flashbackText.style.zIndex = '1000';

      document.body.appendChild(flashbackText);
    
      flashbackText.addEventListener('click', function() {
        // 清空body但保留元素引用
        document.body.innerHTML = '';

        const video = document.createElement('video');
        video.id = 'myVideo';
        video.style.position = 'absolute';
        video.style.top = '50%';
        video.style.left = '50%';
        video.style.transform = 'translate(-50%, -50%) rotate(90deg)';
        video.style.width = '100vh';
        video.style.height = '100vw';
        video.style.objectFit = 'contain';
        video.controls = true; // 开启控件方便调试

        const source = document.createElement('source');
        source.src = './myvideo.mp4'; // 确保文件路径正确
        source.type = 'video/mp4';

        video.appendChild(source);
        document.body.appendChild(video);

        video.onloadedmetadata = function() {
          console.log('Video metadata loaded successfully');
          console.log('Video duration:', video.duration);
          // 元数据加载完成后触发播放,捕获可能的错误
          video.play().catch(err => {
            console.error('Play failed:', err);
          });
        }; 

        video.onerror = function(e) {
          console.error('Error loading the video:', e);
        };      

        video.addEventListener('ended', function() {
          // 视频结束后恢复原页面内容
          clearInterval(clr);
          document.body.innerHTML = '';
          document.body.innerHTML = '<div id="exhaustedTip">Resource Exhausted !<br>You may reload the page or close the tab.</div>';
          document.body.appendChild(centeredText);
          document.body.appendChild(flashbackText);
          document.documentElement.style.overflow = 'hidden';
          document.body.style.overflow = 'hidden';
          // 重新启动文字闪烁效果
          clr = setInterval(flash, 500);
        });    
      });
    } else {
      seconds--;
      setTimeout(updateCountdown, 1000);
    }
  }

  updateCountdown();
}
closePageWithCountdown(1) // 1 sec for testing

关键修改说明

  1. 移除<html>元素的操作:改为直接清空body内容并添加提示文本,避免破坏整个文档结构。
  2. 替换document.write:使用innerHTML添加内容,避免清空文档导致元素丢失。
  3. 视频播放逻辑优化:移除autoplay,在onloadedmetadata回调中触发play()并添加错误捕获,确保在用户交互上下文内执行播放。
  4. 视频结束恢复逻辑:重新构建提示内容和交互元素,恢复文字闪烁效果,避免使用document.write覆盖内容。
  5. 路径检查:确保./myvideo.mp4路径正确,视频文件与当前页面同目录,或使用正确的相对/绝对路径。

关于telegra.ph链接偶尔可用的说明

这大概率是因为远程视频的跨域策略、缓存机制或浏览器自动播放策略的差异,但核心问题还是你的DOM操作错误,修复后本地视频也能正常运行。


内容的提问来源于stack exchange,提问作者stranger555

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:25:55