Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

157
Visualizações
Differentiate user scroll from anchor scroll

In my Javascript code I'm listening for the scroll event and doing some work whenever it fires:

document.addEventListener(
    'scroll',
    (event) => {
        // do something
    },
    { passive: true }
);

I have a nav bar which contains anchors to different sections on my page, which when clicked causes the page to scroll down to the section (and fires the scroll event):

<nav class="navbar">
    <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link nav-link-jump" href="#anchor-1">Popular Items</a>
        </li>
    </ul>
</nav>

...

<section id="anchor-1">...</section>

However, I do not want the scroll event to fire when the page scrolls as a result of clicking on the anchor link. I only want it to fire when the user actually scrolls (i.e. with mouse wheel or by swiping).

I couldn't find any field in the 'event' object that would differentiate the two scroll sources but perhaps I missed something.

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

The scroll event takes the most generic Event interface so there are no properties for differentiating the scroll source. I think it is basically unfeasible without completely overriding the default scroll anchor behaviour with your own JS. Having tried to do similar things in the past and ended up with horrible results, I would not recommend it.

You might want to think about doing this in reverse: disable anything you don't want to happen when a user clicks on the link, then renable it the next time a wheel or touchmove event is triggered. These events are particular to user scroll behaviour and won't be triggered by an anchor link.

const link = document.querySelector("a");
const counter = document.querySelector("p");
const target = document.querySelector("#target");

let userScrolling = true;

link.addEventListener("click", () => userScrolling = false);

window.addEventListener("wheel", () => userScrolling = true);
window.addEventListener("touchmove", () => userScrolling = true);
window.addEventListener("mousedown", () => userScrolling = true);

window.addEventListener("scroll", () => {
  if (!userScrolling) return;
  counter.textContent = parseInt(counter.textContent) + 1;
});
html {
  scroll-behavior: smooth;
}

p {
  position: fixed;
  bottom: 0;
  right: 0;
  padding: 16px;
}

.separator, #target {
  height: 100vh;
}
<a href="#target">Link</a>
<p>0</p>
<div class="separator"></div>
<div id="target">Target<div>

You'll notice that there's a mousedown handler in there too. That's so we can enable user scrolling again by manually clicking and dragging the scrollbar, and also by clicking the middle-wheel compass. Unfortunately either one or multiple scroll events will still slip through depending on the browser if you use mousedown while the anchor scroll is in progress.

You could also go a step further to alleviate this issue and make sure the mouse event is from a middle wheel button event.button = 1, or is triggered over a scrollbar. This second factor is potentially complicated and beyond the scope of the question so I leave you with this answer which is the most promising I could find.

Honestly though, I think the takeaway here should be don't try to do this. The reason you can't distinguish user/anchor in the event is because they are functionally identical - a user clicking a button to scroll for them is user scroll behaviour and it should not realistically cause a problem. If you have some scroll-based animation you need to skip over, it might be better to just remove smooth-scrolling behaviour instead and reset the animation values in the background.

about 4 years ago · Juan Pablo Isaza Relatório

0

let navElements = document.getElementsByClassName("nav-link")[0]
let scroll = true

navElements.addEventListener("click", function () {
  scroll = false
});



document.addEventListener(
    'scroll',
    (event) => {
        if ( scroll === true ) {
            // do something
        } 
        scroll = true
       
        
    },
    { passive: true }
);
<nav class="navbar">
    <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link nav-link-jump" href="#anchor-1">Popular Items</a>
        </li>
    </ul>
</nav>

...

<section id="anchor-1">...</section>

My approach

  1. I initialize a element scroll, set to true.
  2. I set another eventListener for the navbar link. Whenever it is clicked, scroll's value changes to false.
  3. Then in your scroll eventListener, only do something if scroll === true, meaning it's not the nav-link that was clicked.
  4. Lastly, I reset scroll's value to it's original state true.
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda