如何让jQuery视频播放脚本仅触发一次?
解决滚动触发视频播放重复执行的问题
场景代码
HTML
<div class="block"><span>Video below</span></div> <div class="block video-block"> <video class="video" loop="loop" width="640" controls="controls" muted> <source src="http://denis-creative.com/wp-content/uploads/2018/01/video.mp4" type="video/mp4" /> <source src="http://denis-creative.com/wp-content/uploads/2018/01/video.ogv" type="video/ogv" /> <source src="http://denis-creative.com/wp-content/uploads/2018/01/video.webm" type="video/webm" /> </video> </div> <div class="block"><span>Video above</span></div>
CSS
.block{ height: 100vh; font-size: 60px; text-align: center; display: flex; } .block > *{ margin: auto; display: inline-block; max-width: 100%; }
原JS(含isInViewport插件)
// Plugin isInViewport !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery"),require("window")):"function"==typeof define&&define.amd?define("isInViewport",["jquery","window"],n):n(e.$,e.window)}(this,function(e,n){"use strict";function t(n){var t=this;if(1===arguments.length&&"function"==typeof n&&(n=[n]),!(n instanceof Array))throw new SyntaxError("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions");return n.forEach(function(n){"function"!=typeof n?(console.warn("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions"),console.warn("isInViewport: Ignoring non-function values in array and moving on")):[].slice.call(t).forEach(function(t){return n.call(e(t))})}),this}function o(n){var t=e("<div></div>").css({width:"100%"});n.append(t);var o=n.width()-t.width();return t.remove(),o}function r(t,i){var a=t.getBoundingClientRect(),u=a.top,c=a.bottom,f=a.left,l=a.right,d=e.extend({tolerance:0,viewport:n},i),s=!1,p=d.viewport.jquery?d.viewport:e(d.viewport);p.length||(console.warn("isInViewport: The viewport selector you have provided matches no element on page."),console.warn("isInViewport: Defaulting to viewport as window"),p=e(n));var w=p.height(),h=p.width(),v=p[0].toString();if(p[0]!==n&&"[object Window]"!==v&&"[object DOMWindow]"!==v){var g=p[0].getBoundingClientRect();u-=g.top,c-=g.top,f-=g.left,l-=g.left,r.scrollBarWidth=r.scrollBarWidth||o(p),h-=r.scrollBarWidth}return d.tolerance=~~Math.round(parseFloat(d.tolerance)),d.tolerance<0&&(d.tolerance=w+d.tolerance),l<=0||f>=h?s:s=d.tolerance?u<=d.tolerance&&c>=d.tolerance:c>0&&u<=w}function i(n){if(n){var t=n.split(",");return 1===t.length&&isNaN(t[0])&&(t[1]=t[0],t[0]=void 0),{tolerance:t[0]?t[0].trim():void 0,viewport:t[1]?e(t[1].trim()):void 0}}return{}}e="default"in e?e.default:e,n="default"in n?n.default:n,e.extend(e.expr[":"],{"in-viewport":e.expr.createPseudo?e.expr.createPseudo(function(e){return function(n){return r(n,i(e))}}):function(e,n,t){return r(e,i(t[3]))}}),e.fn.isInViewport=function(e){return this.filter(function(n,t){return r(t,e)})},e.fn.run=t}); //# isInViewport // Play Video $(function() { var $video = $('.video'); var $window = $(window); $window.scroll(function() { if ($video.is(":in-viewport")) { $video[0].play(); } else { $video[0].pause(); } }); });
问题分析
原代码在滚动时会反复检测视频是否处于视口内,每次检测到都会调用play(),导致视频重复触发播放动作(比如卡顿、重新开始播放)。你尝试的布尔值控制和one()方法未生效,大概率是逻辑位置或使用方式有误。
解决方案
方案一:布尔标记控制播放仅执行一次
通过一个变量标记视频是否已触发过播放,确保play()只执行一次,同时保留离开视口暂停的逻辑:
$(function() { var $video = $('.video'); var $window = $(window); var hasPlayed = false; // 标记是否已触发过播放 $window.scroll(function() { // 仅当视频在视口内且未播放过时,执行播放 if ($video.is(":in-viewport") && !hasPlayed) { $video[0].play(); hasPlayed = true; // 更新标记,避免重复触发 } // 视频不在视口内且正在播放时,暂停 else if (!$video.is(":in-viewport") && !$video[0].paused) { $video[0].pause(); } }); });
如果希望播放一次后完全停止监听滚动,可以在设置hasPlayed = true后添加:
$window.off('scroll'); // 解绑所有滚动事件监听
方案二:解绑特定滚动监听函数(更精准)
给滚动监听函数命名,当首次检测到视频进入视口时,解绑该特定监听,确保播放仅触发一次:
$(function() { var $video = $('.video'); var $window = $(window); // 定义专门检测视频进入视口的滚动监听函数 function checkVideoViewport() { if ($video.is(":in-viewport")) { $video[0].play(); $window.off('scroll', checkVideoViewport); // 解绑当前监听,避免重复触发 } } $window.scroll(checkVideoViewport); // 单独保留离开视口暂停的逻辑 $window.scroll(function() { if (!$video.is(":in-viewport") && !$video[0].paused) { $video[0].pause(); } }); });
注意事项
- 视频的
muted属性必须保留,现代浏览器限制无交互的自动音频播放。 - 确保
isInViewport插件已正确加载,无版本冲突。
内容的提问来源于stack exchange,提问作者user9671171
相关产品推荐
相关产品推荐

