【问题标题】:play video in loop using setTimeout使用 setTimeout 循环播放视频
【发布时间】:2020-03-11 12:03:57
【问题描述】:

我想循环播放视频。出于某种原因,我不想在结束事件上更改视频 src。 所以我在一个循环中为每个视频创建了视频元素。我还有视频 src 和数组中的持续时间。

这是我的想法: 只有当前正在播放的视频标签可见。其他人将被隐藏。 我想使用 setTimeout 函数,而不是使用结束事件。视频的时长将是延迟参数。

但他们都一起玩。我无法让他们按顺序播放。

这是我到目前为止所做的:

videoArray = [
    {"video":video1.mp4, "duration": 5},
    {"video":video2.mp4, "duration": 7},
    {"video":video3.mp4, "duration": 9},
    {"video":video4.mp4, "duration": 10},
]

for (var j = 0; j < videoArray.length; j++){
    var video = document.createElement("video");
    video.src=videoArray[j];
    video.id="video-"+j;
    video.preload = "metadata";
    video.type="video/mp4";
    video.autoplay = true; 
    video.style.display="none";
    document.body.appendChild(video); 
}

for (var count = 0; count < videoArray.length; count++) {
    (function(num){
        setTimeout(function() {
            videoArray[num].video.style.display="block";
            videoArray[num].video.play();
        }, 1000 * videoArray[num].duration);
        videoArray[num].video.style.display="none";
    })(count);
}

【问题讨论】:

  • 您需要使用timeupdateplaypause 事件侦听器,而不是尝试使用setTimeout 并记住这一点:developers.google.com/web/updates/2017/06/…
  • 为什么要使用 setTimeout 来做
  • 请记住,用户可以在 Firefox 的上下文菜单中更改视频速度。不确定其他浏览器。
  • 我添加了第二个使用setTimeout 的答案。同样,我不建议采用这种方法,但它是可行的。

标签: javascript html html5-video settimeout


【解决方案1】:

免责声明

我知道这个问题是在没有 ended 事件的情况下提出的,但我不认为设置超时是要走的路。
考虑一下您的视频缓冲或因任何原因放慢速度的场景,您的 setTimeout 将不同步。

在底部,我添加了另一个解决方案来满足不使用ended 事件的要求,但同样,我不建议使用它。

解决方案

我们的想法是在视频结尾设置一个事件侦听器,在这种情况下,即使您以不同的速度播放视频,无论持续时间长短,您仍将播放下一个视频。

另一个好处是您一开始就不需要知道视频的持续时间。

PS。 你需要监听的事件监听器是video.addEventListener("ended", callback);

非常欢迎您运行代码或查看working example I've created for you

工作示例

    const videoUrls = [
        'https://videos-play-loop.netlify.com/video1.mp4',
        'https://videos-play-loop.netlify.com//video2.mp4',
        'https://videos-play-loop.netlify.com//video3.mp4',
    ];

    const createVideo = ({id, src, width, cls = 'video', display = 'block', playbackRate = 1, muted = true, type = 'video/mp4', autoplay = false, controls = true}) => {
        const videoElement = document.createElement("video");
        videoElement.id = id;
        videoElement.src = src;
        videoElement.classList.add(src);
        videoElement.type = type;
        videoElement.autoplay = autoplay;
        videoElement.controls = controls;
        videoElement.style.display = display;
        videoElement.muted = muted;
        videoElement.playbackRate = playbackRate;
        return videoElement;
    };


    const addVideos = (container, videoUrls) => {
        const videos = videoUrls.map((url, index) => {
            const first = index === 0;
            const display = first ? 'block' : 'none';
            return createVideo({id: `video-${index}`, src: url,display, width: 640, autoplay: first, playbackRate: 3});
        });
        videos.forEach((video, index) => {
            const last = index === videos.length - 1;
            const playNext = (element) => {
                element.target.style.display = "none";
                const nextElementIndex = last ? 0 : index + 1;
                const nextElement = videos[nextElementIndex];
                nextElement.autoplay = true;
                nextElement.style.display="block";
                nextElement.load();
            };
            video.addEventListener("ended", playNext);
            container.appendChild(video)
        });
    };
    const videoWrapper = document.getElementById('video-wrapper');
    addVideos(videoWrapper, videoUrls);
#video-wrapper video {
    max-width: 600px;
}
&lt;div id="video-wrapper"&gt;&lt;/div&gt;

使用 setTimeout 的工作解决方案(请使用上面的解决方案)

const videoUrls = [{
    url: `https://videos-play-loop.netlify.com/video3.mp4`,
    duration: 3,
  },
  {
    url: `https://videos-play-loop.netlify.com/video2.mp4`,
    duration: 4
  },
  {
    url: `https://videos-play-loop.netlify.com/video1.mp4`,
    duration: 5
  }
];


const createVideo = ({
  id,
  src,
  width,
  cls = 'video',
  display = 'block',
  duration,
  playbackRate = 1,
  muted = true,
  type = 'video/mp4',
  autoplay = false,
  controls = true
}) => {
  const videoElement = document.createElement("video");
  videoElement.id = id;
  videoElement.src = src;
  videoElement.classList.add(src);
  videoElement.type = type;
  videoElement.autoplay = autoplay;
  videoElement.controls = controls;
  videoElement.style.display = display;
  videoElement.muted = muted;
  videoElement.playbackRate = playbackRate;
  videoElement.setAttribute('data-duration', duration);
  return videoElement;
};

const playNext = (videos, index) => {
  const current = videos[index];
  const activeVideoDuration = parseInt(current.dataset.duration) * 1000;
  setTimeout(() => {
    const last = index === videos.length - 1;
    current.style.display = "none";
    current.pause();
    const activeVideoIndex = last ? 0 : index + 1;
    const next = videos[activeVideoIndex];
    next.autoplay = true;
    next.style.display = "block";
    next.load();
    next.play();
    playNext(videos, activeVideoIndex);
  }, activeVideoDuration);
};


const addVideos = (container, videoUrls) => {
  const videos = videoUrls.map((video, index) => {
    const {
      url,
      duration
    } = video;
    const first = index === 0;
    const display = first ? 'block' : 'none';
    return createVideo({
      id: `video-${index}`,
      src: url,
      duration,
      display,
      width: 640,
      autoplay: first,
    });
  });

  videos.forEach(video => container.appendChild(video));
  playNext(videos, 0);
};

const videoWrapper = document.getElementById('video-wrapper');
addVideos(videoWrapper, videoUrls);
#video-wrapper video {
  max-width: 600px;
}
&lt;div id="video-wrapper"&gt;&lt;/div&gt;

【讨论】:

    【解决方案2】:

    您可以将视频的持续时间保存在一个变量中,并将此变量与之前的视频持续时间相加,并将其设置为 setTimeOut 持续时间。

    请注意,视频的时间以秒为单位。对于第一个要播放的视频,用户必须进行交互,否则视频将无法播放。

    工作示例:

    function startVideos(event) {
     event.target.style.display= "none";
            (function() {
              videoArray = [
                {
                  video:
                    "http://techslides.com/demos/sample-videos/small.mp4",
                  duration: 5
                },
                {
                  video:
                    "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
                  duration: 60
                },
                {
                  video:
                    "https://mobamotion.mobatek.net/samples/sample-mp4-video.mp4",
                  duration: 120
                },
                {
                  video:
                    "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
                  duration: 600
                }
              ];
    
              let videArrayElem = [];
    
              for (var j = 0; j < videoArray.length; j++) {
                var video = document.createElement("video");
                video.src = videoArray[j].video;
                video.id = "video-" + j;
                video.preload = "metadata";
                video.type = "video/mp4";
                video.autoplay = false;
                video.controls= true;
                video.style.display = "none";
                videArrayElem.push(video);
                document.body.appendChild(video);
              }
    
              let prviousVideoDuration = 0;
              for (var count = 0; count < videoArray.length; count++) {
                (function(num) {
                  setTimeout(function() {
                    videArrayElem[num].style.display = "block";
                    videArrayElem[num].play();
                  }, prviousVideoDuration);
                  prviousVideoDuration += 1000 * videoArray[num].duration;
                  videArrayElem[num].style.display = "none";
                })(count);
              }
            })();
          }
    video {
            height: 100px;
            width: 100px;
            display: inline-block;
            margin: 4px;
            float: left;
          }
    &lt;button type="button" onclick="startVideos(event)"&gt;Start Video Demo&lt;/button&gt;

    【讨论】:

    • 抱歉回复晚了。我无法在此处检查导致 covid-19 问题的原因。这个可行的解决方案正是我想要的。
    【解决方案3】:

    除了你试图实现一些奇怪的东西,而且你的代码示例无法编译。正如我所见,你已经明白了。 唯一缺少的是pause()display = "none"。只需最少的修改,您就拥有所需的一切。

    const videoArray = [
        {"video":"video1.mp4", "duration": 5}, // of cause you need "" 
        {"video":"video2.mp4", "duration": 7},
        {"video":"video3.mp4", "duration": 9},
        {"video":"video4.mp4", "duration": 10},
    ]
    
    for (let j = 0; j < videoArray.length; j++){
        const video = document.createElement("video");
        // you need to save DOM nodes somewhere to use them in the second loop
        videoArray[j].video_el = video
        video.src=videoArray[j].video; // `.video` is added
        video.id="video-"+j;
        video.preload = "metadata";
        video.type="video/mp4";
        video.autoplay = true; 
        video.style.display="none";
        document.body.appendChild(video); 
    }
    
    for (var count = 0; count < videoArray.length; count++) {
        (function(num){
            setTimeout(function() {
                // add this to hide previous video node and stop video from playing 
                if( num ) {
                    videoArray[num-1].video_el.style.display="none";
                    videoArray[num-1].video_el.pause()
                }
                // videoArray[num].video - is a string, not a DOM node
                // so, you need to change this:
                // videoArray[num].video.style.display="block";
                // for this:
                videoArray[num].video_el.style.display="block";
                // no need. `autoplay` is set to `true` in the first loop
                // videoArray[num].video_el.play();
            }, 1000 * videoArray[num].duration);
            // no need. already done in the first loop
            // videoArray[num].video_el.style.display="none";
        })(count);
    }
    

    但是有很多缺陷:

    1. setTimeout 不关心网络延迟和其他与时间相关的问题,因此您的视频序列很可能无法无缝播放。
    2. 由于第一个流程以及我怀疑 duration 的值是否准确,您应该使用 pause()
    3. 正如@IslamElshobokshy 在 cmets 中指出的那样,使用 play/pause 对您提出的问题并不那么简单。
    4. 如果用户打开页面后什么都不做,你会得到:

      Uncaught (in promise) DOMException: play() failed 因为用户没有先与文档交互。

      在 Chrome 中。和

      只有在用户批准、用户激活网站或媒体静音时才允许自动播放。
      NotAllowedError:当前上下文中用户代理或平台不允许播放方法,可能是因为用户拒绝了权限。

      在 Firefox 中。

    所以你可能最好还是使用ended 事件和muted 属性(以缓解最后一个问题):

    for (let j = 0; j < videoArray.length; j++){
        const video = document.createElement("video")
        videoArray[j].video_el = video
    
        video.src      = videoArray[j].video
        video.id       = "video-"+j
        video.preload  = "metadata"
        video.type     = "video/mp4"
        video.autoplay = true
    
        // show the first video right away
        if( j !== 0 ) video.style.display = "none"
        // set muted attribute
        video.muted = "muted"
        // play next video after the previous had ended
        video.addEventListener('ended', (num => function() {
            this.style.display = "none";
            if( num !== videoArray.length-1 ) {
                videoArray[num+1].video_el.style.display="block";
                // only needed if `muted` is not set 
                videoArray[num+1].video_el.play();
            }
        })(j), false);
    
        document.body.appendChild(video); 
    }
    

    如果muted 属性不是选项,您可以在body 上添加一些事件侦听器,以便在用户开始与页面交互后立即在第一个视频上调用play()。也许你想在这里阅读更多关于autoplay的信息:https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

    【讨论】:

      猜你喜欢
      • 2015-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 2021-12-13
      • 2020-10-19
      • 1970-01-01
      相关资源
      最近更新 更多