Spanky
Spanky

Reputation: 709

Trigger a scrolling event in a different div when a user scrolls using jQuery

I have two div elements:

When a user scrolls div #element-A and #header-one-target reaches the top of the containing div the last element (#animate-hd-b) in #element-B should scroll to the top of the containing div with a nice animation .

Here's the code that I'm working with to start. The code below does something when the window is scrolled not the div.

$(window).scroll(function() {

  var offsetTop = $('#animate-hd-b').offset().top,
    outerHeight = $('#animate-hd-b').outerHeight(),
    windowHeight = $(window).height(),
    scrollTop = $(this).scrollTop();

  console.log((offsetTop-windowHeight) , scrollTop);

  if (scrollTop > (offsetTop+outerHeight-windowHeight)){
    alert('you have scrolled to the top!');
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="element-A" style="background: orange; overflow: auto;">
  <div class="content" style="padding-bottom: 300px;">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <h1 id="header-one-target">Header One</h1>
  </div>
</div>

<div id="element-B" style="background: yellow; overflow: auto;">
  <div class="content" style="padding-bottom: 300px;">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <h1 id="animate-hd-b">Animate This Header</h1>
  </div>
</div>

Is there a way to do this in jQuery?

Upvotes: 8

Views: 2302

Answers (2)

Shikkediel
Shikkediel

Reputation: 5205

Some conditions were added that should prevent unnecessary animations and queueing (which tends to happen when listening for scroll and animating scrollTop). It keeps track of the scroll direction and won't start animating when the element on the right has already reached its position.

Codepen demo

var sin = $('#element-A'),
dex = $('#element-B'),
peg = sin.scrollTop();

sin.scroll(function() {

  var way = sin.scrollTop(),
  rate = Math.round(sin.find('h1').position().top),
  area = dex.scrollTop(),
  turf = Math.round(dex.find('h1').position().top),
  down = way > peg;
  peg = way;

  // conditions for scrolling down

  if (rate < 0 && down && turf) {
    dex.not(':animated').animate({scrollTop: area+turf}, 700);
  }

  // scrolling up

  if (!down && area) {
    dex.not(':animated').animate({scrollTop: 0}, 700);
  }
});
body {
  margin: 0;
}

body > div {
  width: 50%;
  height: 100vh;
  float: left;
  overflow: auto;
}

#element-A {
  background: orange;
}

#element-B {
  background: yellow;
}

.content {
  padding-bottom: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="element-A">
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <h1 id="header-one-target">Header One</h1>
  </div>
</div>

<div id="element-B">
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <h1 id="animate-hd-b">Animate This Header</h1>
  </div>
</div>

In case the elements are differently positioned in the target environment, using position() is a more straightforward approach than offset() because the latter is relative to the document. The former (used here) is relative to its own parent element and should work independent of its position.

Upvotes: 3

Munim Munna
Munim Munna

Reputation: 17546

This is really pretty simple. You just keep track of #header-one-target and animate #animate-hd-b when #header-one-target reaches at the top.

(function($) {
  let $elementA = $('#element-A');
  let $elementB = $('#element-B');
  let $headerOneTarget = $('#header-one-target');
  let $animateHdB = $('#animate-hd-b');
  let isScrollAtTop = true;
  $elementA.scroll(function() {
    if (isScrollAtTop && $headerOneTarget.offset().top < 5) {
      isScrollAtTop = false;
      $elementB.animate({
        scrollTop: $elementB.scrollTop() + $animateHdB.offset().top
      });
    } else if ($elementA.scrollTop() < 5) {
      isScrollAtTop = true;
      $elementB.animate({
        scrollTop: 0
      });
    }
  });
})(jQuery);
#element-A {
  background: orange;
  overflow: auto;
  height: 100vh;
  width: 60vw;
  position: fixed;
  top: 0;
  left: 0;
}

#element-B {
  position: fixed;
  top: 0;
  right: 0;
  height: 100vh;
  width: 40vw;
  background: yellow;
  overflow: auto;
}

.content {
  padding: 10px;
}

.content-vh100 {
  height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="element-A">
  <div class="content">
    <p>Scroll</p>
    <p>to</p>
    <p>header</p>
    <p>one</p>
    <h1 id="header-one-target">Header One</h1>
    <div class="content-vh100"></div>
  </div>
</div>

<div id="element-B">
  <div class="content">
    <p>to</p>
    <p>animate</p>
    <p>following</p>
    <p>content</p>
    <h1 id="animate-hd-b">Animate This Header</h1>
    <div class="content-vh100"></div>
  </div>
</div>

Upvotes: 4

Related Questions