Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 302
Spanky Avatar asked Mar 21 '19 20:03

Spanky


2 Answers

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>
like image 160
Munim Munna Avatar answered Oct 06 '22 06:10

Munim Munna


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.

like image 33
Shikkediel Avatar answered Oct 06 '22 06:10

Shikkediel