使用 setTimeout 循环播放视频
play video in loop using setTimeout
我想循环播放视频。出于某种原因,我不想在结束的事件中更改视频源。
所以我为循环中的每个视频创建了视频元素。我还有数组中的视频 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);
}
您可以将视频的持续时间保存在一个变量中,并将该变量与之前的视频持续时间相加,并将其设置为 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;
}
<button type="button" onclick="startVideos(event)">Start Video Demo</button>
除此之外,您正在尝试实现一些奇怪的事情,并且您的代码示例无法编译。正如我所见,你已经明白了。
唯一缺少的是 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);
}
但是有很多瑕疵:
setTimeout
不关心网络延迟和其他与时间相关的问题,因此很可能您的视频序列无法无缝播放。
- 由于第一个流程以及我怀疑
duration
值是否准确,您应该使用 pause()
.
- 正如@IslamElshobokshy 在对您的问题的评论中指出的那样,使用
play/pause
并不是那么简单。
如果用户打开页面后什么都不做,你会得到:
Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
在 Chrome。并且
Autoplay is only allowed when approved by the user, the site is activated by the user, or media is muted.
NotAllowedError: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
在 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
免责声明
I know that the question was asked without the ended
event, but I do not think that set time out is the way to go.
Think of the scenario where you have video buffering, or slowing down for any reason, your setTimeout will be out of sync.
At the bottom I've added another solution that answers the requirement of not using the ended
event, but again, I do not recommend using it.
解决方案
我们的想法是让一个事件侦听器监听到视频的结尾,在这种情况下,即使您 运行 以不同的速度播放视频,您仍然会 运行 下一个视频不分时长。
另一个好处是您一开始就不需要知道视频的时长。
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;
}
<div id="video-wrapper"></div>
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;
}
<div id="video-wrapper"></div>
我想循环播放视频。出于某种原因,我不想在结束的事件中更改视频源。 所以我为循环中的每个视频创建了视频元素。我还有数组中的视频 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);
}
您可以将视频的持续时间保存在一个变量中,并将该变量与之前的视频持续时间相加,并将其设置为 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;
}
<button type="button" onclick="startVideos(event)">Start Video Demo</button>
除此之外,您正在尝试实现一些奇怪的事情,并且您的代码示例无法编译。正如我所见,你已经明白了。
唯一缺少的是 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);
}
但是有很多瑕疵:
setTimeout
不关心网络延迟和其他与时间相关的问题,因此很可能您的视频序列无法无缝播放。- 由于第一个流程以及我怀疑
duration
值是否准确,您应该使用pause()
. - 正如@IslamElshobokshy 在对您的问题的评论中指出的那样,使用
play/pause
并不是那么简单。 如果用户打开页面后什么都不做,你会得到:
Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
在 Chrome。并且
Autoplay is only allowed when approved by the user, the site is activated by the user, or media is muted.
NotAllowedError: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.在 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
免责声明
I know that the question was asked without the
ended
event, but I do not think that set time out is the way to go.
Think of the scenario where you have video buffering, or slowing down for any reason, your setTimeout will be out of sync.At the bottom I've added another solution that answers the requirement of not using the
ended
event, but again, I do not recommend using it.
解决方案
我们的想法是让一个事件侦听器监听到视频的结尾,在这种情况下,即使您 运行 以不同的速度播放视频,您仍然会 运行 下一个视频不分时长。
另一个好处是您一开始就不需要知道视频的时长。
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;
}
<div id="video-wrapper"></div>
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;
}
<div id="video-wrapper"></div>