使用纯JS滚动到使用div(不是窗口)的位置

时间:2015-07-13 10:37:04

标签: javascript scroll anchor

PURE JS只会请 - 没有JQUERY

我有一个带溢出滚动的div,窗口(html / body)永远不会溢出。

我有一个锚链接列表,想要点击它们时滚动到某个位置。

基本上只是在div中寻找锚点滚动,而不是窗口。

window.scrollTo等不起作用,因为窗口永远不会溢出。

简单测试用例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只会请 - 没有JQUERY

2 个答案:

答案 0 :(得分:4)

您想要的是设置scrollTop property on 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;
    }
  });

你会注意到我做了不同的其他几件事:

  • 我使用了event delegation,所以我只需要将一个事件附加到nav元素,这样可以更有效地处理任何链接上的点击。
  • 同样,我没有循环遍历所有p元素,而是使用attribute selector
  • 选择了我想要的元素

这不仅更高效,更具可扩展性,而且还可以生成更短,更易于维护的代码。

此代码只会跳转到元素,对于动画滚动,您需要编写incrementally updates scrollTop after small 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);
  }
});

事件委派可能遇到的另一个问题是,如果a元素包含子元素并且单击了子元素,则它将成为事件的目标而不是a标记本身。你可以使用像getParentAnchor function I wrote here这样的东西解决这个问题。

答案 1 :(得分:0)

我希望我现在能正确理解这个问题:你有标记,你不能改变(因为它通过某种方式生成你无法控制),并希望使用JS来增加功能生成的菜单项。

我的建议是分别向目标和菜单项添加idhref属性,如下所示:

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');
}