如何仅在用户第一次滚动到某个元素时运行自定义函数

How do I run a custom function ONLY the first time a user scrolls to a certain element?

本文关键字:元素 运行 自定义函数 何仅 用户 第一次 滚动      更新时间:2023-09-26

问题:

我有一个奇特的循环图像转盘,当用户滚动到某个分区时,它需要从特定的第一张幻灯片开始。如果用户上下滚动并返回该分区,它永远不应该重新启动。

我目前只能让它在用户滚动到div时启动——然后当你滚动到它时,它就会出错,我认为这是因为函数再次开始运行。

我正在努力实现的目标:

  1. 用户滚动到某个div
  2. 花式图像转盘动画功能运行
  3. 如果用户向上/向下滚动并返回div,则动画功能将永远不会再次启动

我的(匿名的,对不起!(代码:

http://jsfiddle.net/annablabber/h8pqW/

HTML

<p class="scroll_down">Scroll down...</p>
<div class="animation_container">You should get an alert only once here—the first time you scroll to this div.</div>

CSS

.scroll_down {
  margin-bottom: 1000px;
}
.animation_container {
  width: 300px;
  height: 200px;
  background-color: red;
  padding: 30px;
  color: white;
  margin-bottom: 1000px;
}

jQuery

// The fancy function for my animations
function doSomeComplicatedStuff() {
  alert("...and here's where the complicated animations happen!");
}
// The function to check if div.animation_container is scrolled into view
function isScrolledIntoView(elem)
{
  var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();
  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
  if (isScrolledIntoView('.animation_container')) {
    run_once(function() {
      doSomeComplicatedStuff();
    });
  }
});
// The function that's supposed to make sure my fancy function will only run ONCE, EVER
function run_once( callback ) {
  var done = false;
  return function() {
    if ( !done ) {
      done = true;
      return callback.apply( this, arguments );
    }
  };
} 

为视觉设计师清晰地写出的剧本道歉。如果匿名代码中的问题还不够清楚,请告诉我。

是否将done变量移动到全局?

var firstScroll = false;
$(window).on('scroll', function() {
  if (isScrolledIntoView('.animation_container') && !firstScroll) {
      doSomeComplicatedStuff();
  }
});
function doSomeComplicatedStuff() {
    firstScroll = true;        
    // Your code here
}

这样,isScrolledIntoView第一次返回true时,doComplicatedStuff函数会立即翻转布尔值firstScroll,从而停止后续调用。

你可以有这样的

// The fancy function for my animations
var alreadyRun = false;
function doSomeComplicatedStuff() {
    alert("...and here's where the complicated animations happen!");
}
// The function to check if div.animation_container is scrolled into view
function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
  if (isScrolledIntoView('.animation_container') && !alreadyRun) {
      doSomeComplicatedStuff();
      alreadyRun = true;
  }
});

工作jsfiddle

  1. 将done变量放入全局范围。否则,每次调用run_once()时,它都会被一次又一次地重新定义。更好的方法是向该函数添加第一个参数,以确定是否运行了哪个操作(function run_once(identifier,callback) { if(!done[identifier]) { run function and set done[identifier] to true; }(
  2. run_once()中删除该return function()
  3. 请参见Fiddle

以下是一个更新的解决方案:http://jsfiddle.net/h8pqW/2/

基本上,每次满足条件时都运行run_once,所以它创建了一个新的done变量。我将run_once调用移到doSomeComplicatedStuff声明中,将其转换为只运行一次的方法。

// The fancy function for my animations
var doSomeComplicatedStuff = run_once(function () {
    alert("...and here's where the complicated animations happen!");
});

这里有一个更高性能的替代方案,不需要使用run_once助手:http://jsfiddle.net/h8pqW/3/

在本例中,我只是在调用函数后立即解除scroll事件的绑定。这将阻止页面在每次用户滚动时继续尝试运行该功能。

// If div.animation_container is scrolled into view, run the fancy function
$(window).on('scroll', function() {
  if (isScrolledIntoView('.animation_container')) {
    doSomeComplicatedStuff();
    $(window).unbind('scroll');
  }
});