Scroll to WITHIN div (not window) using pure JS

PURE JS ONLY PLEASE - NO JQUERY

I have a div with scroll overflow, the window (html / body) never overflows itself.

I have a list of linked links and you want to scroll them to the position when clicked.

Basically just looking for scroll anchors from a div, not a window.

window.scrollTo etc. do not work because the window never overflows.

Simple test case http://codepen.io/mildrenben/pen/RPyzqm

JADE

nav a(data-goto="#1") 1 a(data-goto="#2") 2 a(data-goto="#3") 3 a(data-goto="#4") 4 a(data-goto="#5") 5 a(data-goto="#6") 6 main p(data-id="1") 1 p(data-id="2") 2 p(data-id="3") 3 p(data-id="4") 4 p(data-id="5") 5 p(data-id="6") 6 

SCSS

 html, body { width: 100%; height: 100%; max-height: 100%; } main { height: 100%; max-height: 100%; overflow: scroll; width: 500px; } nav { background: red; color: white; position: fixed; width: 50%; left: 50%; } a { color: white; cursor: pointer; display: block; padding: 10px 20px; &:hover { background: lighten(red, 20%); } } p { width: 400px; height: 400px; border: solid 2px green; padding: 30px; } 

Js

 var links = document.querySelectorAll('a'), paras = document.querySelectorAll('p'), main = document.querySelector('main'); for (var i = 0; i < links.length; i++) { links[i].addEventListener('click', function(){ var linkID = this.getAttribute('data-goto').slice(1); for (var j = 0; j < links.length; j++) { if(linkID === paras[j].getAttribute('data-id')) { window.scrollTo(0, paras[j].offsetTop); } } }) } 

PURE JS ONLY PLEASE - NO JQUERY

+6
source share
2 answers

You want to set the scrollTop property in the <main> element .

 var nav = document.querySelector('nav'), main = document.querySelector('main'); nav.addEventListener('click', function(event){ var linkID, scrollTarget; if (event.target.tagName.toUpperCase() === "A") { linkID = event.target.dataset.goto.slice(1); scrollTarget = main.querySelector('[data-id="' + linkID + '"]'); main.scrollTop = scrollTarget.offsetTop; } }); 

You will notice a couple of other things that I did differently:

  • I used event delegation , so I only had to bind one event to the nav element, which would more efficiently handle clicks on any of the links.
  • Similarly, instead of iterating over all p elements, I chose the one that wanted to use the attribute selector

It is not only more efficient and scalable, but also provides shorter and more convenient code.

This code will simply go to the element, for animated scrolling you will need to write a function that gradually updates scrollTop after slight delays using setTimeout .

 var nav = document.querySelector('nav'), main = document.querySelector('main'), scrollElementTo = (function () { var timerId; return function (scrollWithin, scrollTo, pixelsPerSecond) { scrollWithin.scrollTop = scrollWithin.scrollTop || 0; var pixelsPerTick = pixelsPerSecond / 100, destY = scrollTo.offsetTop, direction = scrollWithin.scrollTop < destY ? 1 : -1, doTick = function () { var distLeft = Math.abs(scrollWithin.scrollTop - destY), moveBy = Math.min(pixelsPerTick, distLeft); scrollWithin.scrollTop += moveBy * direction; if (distLeft > 0) { timerId = setTimeout(doTick, 10); } }; clearTimeout(timerId); doTick(); }; }()); nav.addEventListener('click', function(event) { var linkID, scrollTarget; if (event.target.tagName.toUpperCase() === "A") { linkID = event.target.dataset.goto.slice(1); scrollTarget = main.querySelector('[data-id="' + linkID + '"]'); scrollElementTo(main, scrollTarget, 500); } }); 

Another problem that you may encounter when delegating events is that if the elements a contain child elements and a child element is inherited from them, this will be the purpose of the event, not the a tag. You can get around this with the getParentAnchor function that I wrote here .

+3
source

I hope I correctly understood the problem now: you have markup that you cannot change (since it is generated in some way you have no control) and want to use JS to add functionality to the generated menu items.

My suggestion would be to add id and href attributes to objects and menu items respectively:

 var links = document.querySelectorAll('a'), paras = document.querySelectorAll('p'); for (var i = 0; i < links.length; i++) { links[i].href=links[i].getAttribute('data-goto'); } for (var i = 0; i < paras.length; i++) { paras[i].id=paras[i].getAttribute('data-id'); } 
0
source

All Articles