HTML5 和 Javascript 仅在可见时播放视频
Posted
技术标签:
【中文标题】HTML5 和 Javascript 仅在可见时播放视频【英文标题】:HTML5 and Javascript to play videos only when visible 【发布时间】:2014-02-05 11:26:03 【问题描述】:我有兴趣设置一个包含多个视频剪辑的 html 页面,以便每个视频剪辑仅在可见时播放,然后在不可见时暂停。
我已经找到this great example 了解如何使用一个剪辑来实现这一点,但我无法修改代码以使用多个剪辑。也许我需要将此代码转换为函数以便于重用?
这是我到目前为止所拥有的(上面链接的 JS Bin 修改为 2 个剪辑而不是一个)。
此代码似乎只适用于两个剪辑中的一个。
<!DOCTYPE html>
<html>
<!-- Created using jsbin.com Source can be edited via http://jsbin.com/ocupor/1/edit
-->
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
<style>
#right
position: absolute;
top: 2000px;
#video1
position: absolute;
left: 2000px;
top: 2000px;
#video2
position: absolute;
left: 2000px;
top: 3000px;
</style>
<style id="jsbin-css">
</style>
</head>
#
<body style="width: 4000px; height: 4000px;">
<div id="info"></div>
<div id="down">
scroll down please...
</div>
<div id="right">
scroll right please...
</div>
<video id="video1">
<source src="http://video-js.zencoder.com/oceans-clip.mp4"/>
</video>
<script>
var video = document.getElementById('video1'), fraction = 0.8;
function checkScroll()
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction)
video.play();
else
video.pause();
checkScroll();
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
</script>
<video id="video2">
<source src="http://video-js.zencoder.com/oceans-clip.mp4"/>
</video>
<script>
var video = document.getElementById('video2'), fraction = 0.8;
function checkScroll()
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction)
video.play();
else
video.pause();
checkScroll();
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
</script>
</body>
</html>
【问题讨论】:
【参考方案1】:好吧,我想,应该是这样的:
var videos = document.getElementsByTagName("video");
function checkScroll()
var fraction = 0.8; // Play when 80% of the player is visible.
for(var i = 0; i < videos.length; i++)
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction)
video.play();
else
video.pause();
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
【讨论】:
我得到一个“未定义的分数”ReferenceError,但是一旦我添加了定义就可以完美运行:fraction = 0.8; 是的,分数只需要在某个地方定义——不过答案很好:) 这对我不起作用,但作为参考很有用。【参考方案2】:使用isInViewport 插件和jQuery,这是我的任务代码
$('video').each(function()
if ($(this).is(":in-viewport"))
$(this)[0].play();
else
$(this)[0].pause();
)
【讨论】:
我正在尝试让这段代码为我工作,它要简单得多。不过,我遇到了麻烦。由于我已切换到基于 wordpress 的网站,因此我的视频遵循以下示例格式:class="wp-video-shortcode" id="video-1115-1"
有什么方法可以修改 [0] 以使用 video-XXXX-X
格式?
我们可以申请 Vimeo 声明它在 iframe 下运行吗?怎么做?
投反对票,因为 OP 没有指定 jQuery 标签。可以预料,这个问题是针对 vanilla javascript 的。
@KalleH.Väravas 在 2014 年发布此答案时并非如此,而且这些深奥的规则只会阻碍贡献。【参考方案3】:
以上方法似乎都不适合我,但我终于找到了一种方法:你需要the visible
plugin,这里有这段小代码:
$(window).scroll(function()
$('video').each(function()
if ($(this).visible(true))
$(this)[0].play();
else
$(this)[0].pause();
)
);
这将允许任何视频仅在进入视口时播放。通过将visible( true )
替换为visible()
,您可以将其设置为仅在整个视频 DOM 元素在视口中时播放。
【讨论】:
谢谢你! 也谢谢你!正是我所需要的具有多个全屏视频部分的滚动页面,这些部分在 Chrome 和 Mac Safari 上没有表现。使用这个插件和上面的代码修复了everything。再次感谢! 如果你们不想使用插件,请查看this 回答。 您的解决方案效果最好!谢谢【参考方案4】:需要检查视频在滚动过程中是否可见。
$(window).scroll(function()
$('video').each(function()
if ($(this).is(":in-viewport"))
$(this)[0].play();
else
$(this)[0].pause();
)
);
【讨论】:
【参考方案5】:你们都需要与时俱进并使用 IntersectionObserver(以及适当的 polyfill 或 babeifyl)。此脚本将在页面滚动进/出视图时播放/暂停页面上的所有视频。轰隆隆。
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver%2CIntersectionObserverEntry"></script>
<script>
let video = document.querySelector('video');
let isPaused = false;
let observer = new IntersectionObserver((entries, observer) =>
entries.forEach(entry =>
if(entry.intersectionRatio!=1 && !video.paused)
video.pause();
isPaused = true;
else if(isPaused)
video.play();
isPaused=false
);
, threshold: 1);
observer.observe(video);
</script>
source
【讨论】:
有点好奇isPaused
标志在做什么。它是某种性能标志,还是效果所必需的?
看起来应该去掉。
是的,可以像if (entry.intersectionRatio !== 1) video.pause() else video.play()
一样简单
css-tricks.com/… - 回头看看视频是否已自动暂停,【参考方案6】:
老问题,但只是想加两分钱,我最初从上面的 jQuery 代码开始,但在实现时遇到了一些问题。此解决方案应该适用于多个视频,并且还可以防止用户暂停视频并尝试滚动并重新开始的问题:
<script>
var videoList = [];
var scrollPauseList = [];
var clickedPauseList = [];
</script>
<script>
var myScrollFunc = function()
$(".video-js").each(function()
var inView = $(this).is(":in-viewport");
var isPaused = $(this)[0].player.paused();
var playerIdx = videoList.indexOf(this.id);
var scrollPaused = scrollPauseList[playerIdx];
var clickPaused = clickedPauseList[playerIdx];
if (inView)
var hasEnded = $(this)[0].player.ended();
var curTime = $(this)[0].player.currentTime();
var hasStarted = curTime > 0;
if(hasStarted && !hasEnded && !clickPaused)
scrollPauseList[playerIdx] = false;
$(this)[0].player.play();
else if(!isPaused)
scrollPauseList[playerIdx] = true;
$(this)[0].player.pause();
);
;
$(window).scroll(myScrollFunc);
</script>
<video
class="video-js" controls></video>
<script>
$(".video-js").each(function()
videoList[videoList.length] = this.id;
scrollPauseList[scrollPauseList.length] = false;
clickedPauseList[scrollPauseList.length] = false;
);
for(var i = 0; i < videoList.length; i++)
var playerID = videoList[i];
var player = videojs(playerID);
player.on('pause', function()
var pID = videoList.indexOf(this.id());
if(!scrollPauseList[pID])
clickedPauseList[pID] = true;
scrollPauseList[pID] = false;
else
clickedPauseList[pID] = false;
scrollPauseList[pID] = false;
);
</script>
我已经清理了一些东西,并且我正在使用 video-js,因此您可能需要对其进行一些修改以使您的实现正常工作。
【讨论】:
【参考方案7】:使用 jQuery、isInViewport 和 Coffeescript,我的完整解决方案如下所示:
$(window).scroll ->
$('video:in-viewport').each -> $(@)[0].play()
$('video:not(:in-viewport)').each -> $(@)[0].pause()
【讨论】:
【参考方案8】:尝试了许多解决方案,唯一部分工作的是下面发布的一个。问题是页面上有3个视频,第二个和第三个基本上由第一个控制。
所以他们在页面加载时开始播放(虽然他们应该在视口中播放)并且在第一次暂停时暂停,有什么建议可以处理多个视频吗?
尝试使用getElementById
但没有用,还尝试了 jquery 插件但没有好的结果。
这里有 www 页面,您可以在其中查看发生的情况以及所有源代码。
http://185.197.128.183/~monompro/
window.onload = function()
var videos = document.getElementsByTagName("video"),
fraction = 0.8;
function checkScroll()
for (var i = 0; i < videos.length; i++)
var video = videos[i];
var x = video.offsetLeft,
y = video.offsetTop,
w = video.offsetWidth,
h = video.offsetHeight,
r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction)
video.play();
else
video.pause();
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
【讨论】:
【参考方案9】:这就是我仅在用户滚动到视频时才设法播放视频的方法。 我使用了 IsInViewport 插件。 希望对您有用!
$(window).scroll(function()
var video = $('.yourvideo');
$(video).each(function()
if(video.is(':in-viewport'))
video[0].play();
video.removeClass('yourvideo');
//I removed class to stop repeating the action ".play()" when it is scrolled again.
);
);
【讨论】:
【参考方案10】:如果其他人遇到这个问题,我无法在我的 WordPress 网站上使用 Saike 的解决方案,因为视频是自动嵌入的(MediaElement 播放器)。但是,qwazix 的解决方案经过了一些修改。这是与IsInView plugin 一起使用的jQuery 代码。这是我的包含脚本(放在我的主题文件夹中footer.php
的末尾)。
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="js/isInViewport.min.js" type="text/javascript"></script>
<script src="js/scrollview.min.js" type="text/javascript"></script>
还有 jQuery 代码(修改 400 到你喜欢的容忍度)
$(function()
$(window).scroll(function()
$('.wp-video-shortcode').each(function()
var str = $(this).attr('id');
var arr = str.split('_');
typecheck = arr[0];
if ($(this).is(":in-viewport( 400 )") && typecheck == "mep")
mejs.players[$(this).attr('id')].media.play();
else if (typecheck == "mep")
mejs.players[$(this).attr('id')].media.pause();
);
);
);
我对这段代码的唯一问题是它确实在滚动时重新启动视频剪辑,即使用户暂停。在我的网站上不是一个破坏交易的问题。以下是实际代码:Ultrasoundoftheweek.com
【讨论】:
【参考方案11】:正如here 解释的那样,offsetTop
/offsetLeft
/等。方法比新的getBoundingClientRect
方法更慢且更容易出错。下面是一些工作代码,可以播放在视口中部分可见的任何视频:
function playVisibleVideos()
document.querySelectorAll("video").forEach(video => elementIsVisible(video) ? video.play() : video.pause());
function elementIsVisible(el)
let rect = el.getBoundingClientRect();
return (rect.bottom >= 0 && rect.right >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth));
let playVisibleVideosTimeout;
window.addEventListener("scroll", () =>
clearTimeout(playVisibleVideosTimeout);
playVisibleVideosTimeout = setTimeout(playVisibleVideos, 100);
);
window.addEventListener("resize", playVisibleVideos);
window.addEventListener("DOMContentLoaded", playVisibleVideos);
setTimeout
的内容可确保在用户滚动时,playVisibleVideos()
函数的调用频率不会超过每 100 毫秒一次(因此不会导致延迟)。
请注意,对于大多数人来说,似乎@Tristanisginger's answer 使用更现代的IntersectionObserver
方法可能比这种方法更好。
【讨论】:
【参考方案12】:如果您正在寻找一个没有任何依赖关系的简单解决方案,这里是:
let video = document.getElementById('video')
function playVideoOnScroll ()
const threshold = 300 //px above the video to start playing
let offset = video.getBoundingClientRect().top
if (offset < threshold)
demoVideo.play()
else
demoVideo.pause()
window.addEventListener('scroll', playVideoOnScroll, false)
window.addEventListener('resize', playVideoOnScroll, false)
【讨论】:
以上是关于HTML5 和 Javascript 仅在可见时播放视频的主要内容,如果未能解决你的问题,请参考以下文章
在 HTML5 画布上工作时出现 JavaScript (JQuery) 问题