如何停止重复滚动事件?

时间:2015-10-15 20:22:21

标签: javascript dom scroll javascript-events

请有人帮我处理我网站上的活动吗?问题是,每次触发滚动事件时它们都会继续发生。导航菜单位于标题下但在滚动时粘在顶部,但是当我们向后滚动时,我希望它返回到标题下方。我不知道我做错了什么。这是我的代码

var navigation = document.querySelector("nav");
var borderBottom = navigation.getAttribute("border-bottom");
var currentDistance = (document.documentElement.scrollHeight);

addEventListener ("scroll", function() {

if (currentDistance > "90px") {
navigation.style.position = "fixed";
navigation.style.top = "0";
navigation.style.borderBottom = "3px solid rgb(157,0,53)";
}

else removeEventListener ("scroll", function() {
navigation.style.position = "fixed";
navigation.style.top = "0";
navigation.style.borderBottom = "3px solid rgb(157,0,53)";
}
);
});

当页面加载并触发滚动事件时,div会进入,这就是我想要的。但我的问题是,每次触发滚动事件时,框都会继续飞行,而不是停止事件,即保持REOCCURRING。继承了我用它的代码。

var flyInDiv = document.getElementById("flyInDiv");

addEventListener ("scroll", function() {
var programMenu = document.createElement("DIV");

programMenu.className = "programMenu";
programMenu.appendChild(flyInDiv);

document.body.appendChild(programMenu);

programMenu.style.position = "fixed";

});

我网站的网址是agwconitsha.org

非常感谢你们!

3 个答案:

答案 0 :(得分:4)

我看过你的代码&您的网站看起来像是在尝试实现以下目标:

  • 当用户滚过标题
  • 时仅粘贴的粘性导航
  • '飞行的服务时间列表'当用户第一次滚动并留在那里

TL; DR - 我在http://jsfiddle.net/9o7frxp1/4/创建了一个包含此基本行为的jsfiddle。

在上面的小提琴中,我建议使用CSS类来控制导航的粘性,以及飞行div的动画。 JavaScript只是用于根据用户是否滚动以及它们的滚动位置来打开和关闭这些类。

这对于分离JS& amp;的关注点非常有用。 CSS,允许每种语言都做它最擅长的事情,并且意味着代码更容易维护。

为了进一步解释,我们暂时以你的<nav>为例,这篇文章不会太长。查看我上面的jsfiddle链接以获取飞行div - 我已经在代码中添加了注释来解释发生了什么,但如果它没有意义,请告诉我。

所以,我们有一个nav元素:

<nav id="nav">
  Nav
</nav>

我们为<nav>设置了一些样式 - 一些默认样式,然后只有当它还有一个.is-sticky类时才应用一些样式:

#nav {
  width: 100%;
  height: 40px;
}

#nav.is-sticky {
  position: fixed;
  top: 0;
}

在我们的JavaScript中,我们找到<nav>

var navigation = document.getElementById('nav');

现在,我们准备一个在用户滚动时将触发的函数。我们还没有添加任何可以收听滚动的内容 - 我们只是准备好功能。

function addStickyClass() {
  // Every time this function fires, we calculate the scroll position
  var currentDistance = document.body.scrollTop;

  // If we've scrolled 90px down, add the 'is-sticky' class to our nav.
  // If not, remove the 'is-sticky' class.
  if (currentDistance > 90) {
    navigation.className = 'is-sticky';
  } else {
    navigation.className = '';
  }
}

很酷 - 我们几乎准备好了。最后一件事 - 让我们确保每次用户滚动时都会触发上述功能。

window.addEventListener('scroll', addStickyClass);

这意味着我们每次用户滚动时都会询问&#34;它们是否距离窗口顶部90px(或更多)?&#34; - 如果是,导航应该是粘性的,如果不是,它就不应该。

stekhn 是正确的,您还没有正确设法正确实现事件监听器,并且导致您的网页表现得很奇怪。

但是,在我上面的代码示例中,我建议只需要添加一个事件监听器,并且不需要删除它。我还想进一步建议你应该用一种不同的JS和&amp; amp;组合方式来想象这个问题。 CSS,正如我上面提到的那样。

在我的答案中的代码中,我已经简化了一些事情,以便更清楚地解释发生了什么 - 您将在我发布的jsfiddle中看到更精细的版本。

然而,即使我的jsfiddle仍然是您网站上的简化版本,因此您需要对其进行调整 - 请一试,让我知道您是如何进行的。

<强>更新

<强> TL; DR:

我实际上意识到#flyInDiv的代码可能更简单,并且不需要任何布尔值或if语句。在http://jsfiddle.net/9o7frxp1/5/

处解释评论

但是我仍然想解释下面我实施的内容 - 我认为值得了解:

所以,如果你还记得,我们每次用户滚动时都会触发一个函数:

function addStickyClass() {
  // Every time this function fires, we calculate the scroll position
  var currentDistance = document.body.scrollTop;

  // If we've scrolled 90px down, add the 'is-sticky' class to our nav.
  // If not, remove the 'is-sticky' class.
  if (currentDistance > 90) {
    navigation.className = 'is-sticky';
  } else {
    navigation.className = '';
  }
}

每次用户滚动时,此函数都会决定是否向我们的元素添加或删除.is-sticky类。

说到哪 - 我们希望我们的代码根据用户滚动的时间决定其他内容 - 揭示您的#flyInDiv。也许我们可以将它包含在这个代码块中?

#flyInDiv的逻辑是:

  • 由于CSS
  • ,当用户首次登陆页面时,默认情况下该元素是不可见的
  • 在用户的第一次滚动时,由于添加了额外的CSS类,该元素应该出现
  • 该元素应保留在用户访问您网页的其他位置。如果用户正在滚动,我们就不再关心了。

让我们看看它是如何在代码术语中工作的。首先,由于CSS,该元素默认是不可见的。我们有.is-sticky类来使元素可见,但默认情况下该类不在元素上:

#flyInDiv {
  width: 100px;
  height: 100px;

  /* Positioned hard right */
  position: fixed;
  right: 0;

  /* Translated an extra 100px to the right, sending it out of view */
  transform: translateX(100px);
}

#flyInDiv.is-sticky {
  /* No translation, so the element should now simply be hard right */
  transform: translateX(0);
}

舞台设置......我们需要一些JavaScript!

让我们回到我们的addStickyClass()函数 - 但我会从这些示例中移除与<nav>相关的其他代码,以使事情更加清晰。

var flyingDiv = document.getElementById("flyInDiv");

function addStickyClass() {
  flyingDiv.className = "is-sticky";
}

请记住,每次用户滚动时都会被触发(感谢我们之前添加的事件监听器),那么会发生什么?

用户第一次滚动时,该元素将获得.is-sticky类。并且每次用户滚动时它都会被设置。

实际上,这并不会影响您网站的行为,我在最近的小提琴中提到过。如果这个类继续设置在#flyInDiv上,它实际上很好,因为它只是意味着从用户第一次滚动的那一刻起,它就会一直保持可见。

但是,严格来说,此代码只需运行一次。我们只想在第一个滚动事件之后设置.is-sticky类。每次用户滚动时,我们都不需要继续设置它。

对于这个例子,我们侥幸成功,因为当代码flyingDiv.className = "is-sticky";在每个滚动上执行时,它只是不断地覆盖类名。结果:您的flyingDiv始终拥有.is-sticky类。

然而,肯定有很多次你想要强制执行的东西肯定只发生在第一次滚动之后 - 例如,让我们说这个项目你需要使用{{ 1}}在第一次滚动之后向DOM添加一个新的,更复杂的元素,而不是简单地使用CSS使其可见 - 我们绝对无法逃脱该代码不断重复自己 - 它会意味着我们的元素不断被追加!

这就是你要做的事情 - 让我们的代码了解元素是否可见。这样,它可以决定是否需要运行代码。

滚动时,它可以不断询问:

  • 元素是不可见的吗?
    • 否:这必须是第一个卷轴。让它可见!
    • 是:这不是第一次滚动。它已经可见了。很酷,什么都不做。

首先,我们需要一个变量进行评估。我们将其命名,并默认将其设置为appendChild()。为什么?因为变量是false(读取&#34;飞行div是否可见?&#34;),并且在页面上发生任何其他事情之前,正如我们已经提到的那样,答案应该是&#34;无&#34;

重要的是,这发生在外面&amp;任何功能之上。我们在这里设置舞台,我们不希望每次用户滚动时此代码都会继续运行。它只是为了给代码提供我们已有的初始知识 - 当用户访问页面时,但在滚动之前,flyingDivIsVisible是不可见的。

#flyInDiv

接下来,我们将一些内容添加到我们的函数中。至关重要的是,我们添加的新内容位于var flyingDivIsVisible = false; 块中,仅在if为真时运行(或换句话为!flyingDivIsVisible):

flyingDivIsVisible === false

请记住,我们将// Tell our code that the div isn't visible. var flyingDivIsVisible = false; function addStickyClass() { // Only run this code if div isn't visible. if (!flyingDivIsVisible) { flyingDiv.className = "is-sticky"; // Tell our code that the div is visible flyingDivIsVisible = true; } } 设置为&amp;我们的功能之外?所以至少在第一次运行此函数时,var flyingDivIsVisible = false;肯定会评估为真。

但是,只在flyingDivIsVisible === false时运行的东西?好吧,它恰好也改变了flyingDivIsVisible === false。为什么?因为运行的内容是将flyingDivIsVisible = true类添加到.is-sticky,这意味着它现在可见 - 但我们需要通过设置#flyInDiv来为我们的代码提供知识。

因此,从现在开始,每当用户滚动时,我们现在都有flyingDivIsVisible = true,这意味着flyingDivIsVisible = true块中的任何代码都将不再运行。

因此,我们刚刚实现了一些代码,这些代码在用户第一次滚动时运行,但之后再也没有。

为了确保尽可能清楚,让我们看看连续运行两次的函数并分解发生的情况。让我们想象一下,如果div是可见的,我们会不断询问代码。既然我们已经为这种知识提供了方法,那么它可以不断地告诉我们。 PS,我在这个例子中使用了IIFEs - 它们是自己运行的函数,而不是等待单独调用。对于我们同步并连续两次运行代码块的示例更有意义:

if (!flyingDivIsVisible)

顺便说一句,作为事后的想法,如果// Tell our code the div isn't visible var flyingDivIsVisible = false; (function () { // Us: Is the div visible? // Code: No. You told it me it isn't. if (!flyingDivIsVisible) { flyingDiv.className = "is-sticky"; // Tell our code that the div is visible flyingDivIsVisible = true; } })(); (function () { // Us: Is the div visible? // Code: Yes. You told me it was last time I ran this function. if (!flyingDivIsVisible) { // Nothing in this block runs, because the div is visible. flyingDiv.className = "is-sticky"; flyingDivIsVisible = true; } })(); 是这个代码控制的唯一东西,我们也可以在第一次滚动之后删除事件监听器,这样代码就不会这样做。 ; t不再需要滚动(它不需要,对吧?它已经完成了第一次滚动显示div的工作)。

但实际上,我们在与#flyInDiv显示&amp;相同的代码的上下文中想象这一点。隐藏,仍然需要事件监听器继续询问&#34;用户是否滚动?&#34;所有的时间,所以我们不想删除事件监听器。

希望一切都有意义!

答案 1 :(得分:0)

问题是您没有正确添加和删除事件侦听器。每个事件监听器都需要一个目标,一个动作和一个处理程序。

window.addEventListener("scroll", myfunction);
window.removeEventListener("scroll", myfunction);

我建议你将滚动事件监听器挂钩到窗口对象(整个页面)然后你就做了你的魔法。

您还可以使用变量来控制带有变量isOpen

的flyIn元素的状态
var navigation = document.querySelector("nav");
var borderBottom = navigation.getAttribute("border-bottom");
var currentDistance = (document.documentElement.scrollHeight);
var isOpen = false;

window.addEventListener("scroll", navigationHandler);

function navigationHandler() {

    if (currentDistance > "90px") {

        navigation.style.position = "fixed";
        navigation.style.top = "0";
        navigation.style.borderBottom = "3px solid rgb(157,0,53)";
    } else {

        navigation.style.position = "relative";
        navigation.style.borderBottom = "none";
    }
}


var flyInDiv = document.getElementById("flyInDiv");

window.addEventListener("scroll", flyInHandler);

function flyInHandler() {

    if (!isOpen) {
        var programMenu = document.createElement("DIV");
        programMenu.className = "programMenu";
        programMenu.appendChild(flyInDiv);
        document.body.appendChild(programMenu);
        programMenu.style.position = "fixed";

        isOpen = true;
        window.removeEventListener("scroll", flyInHandler);
    }
}

答案 2 :(得分:0)

您可以尝试使用overflow-x:hidden [或] overflow-y:hidden 取决于滚动条的位置。