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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:15:32