我有一个页面,其中一个滚动条包含从数据库动态生成的带有div的表行。每个表行就像一个链接,有点像你在视频播放器旁边看到的YouTube播放列表。

当用户访问页面时,他们所在的选项应该会转到滚动div的顶部。这个功能正在工作。问题是,这有点太过分了。比如他们的选项高了10像素。因此,页面被访问,url被用来识别选择了哪个选项,然后将该选项滚动到滚动div的顶部。注意:这不是窗口的滚动条,这是一个带有滚动条的div。

我正在使用这段代码,使它移动选中的选项到div的顶部:

var pathArray = window.location.pathname.split( '/' );

var el = document.getElementById(pathArray[5]);

el.scrollIntoView(true);

它将它移动到div的顶部,但大约10个像素太高了。 有人知道怎么解决吗?


当前回答

UPD:我已经创建了一个npm包,它比下面的解决方案更好,更容易使用。

我的smoothScroll函数

我采用了Steve Banton的出色解决方案,并编写了一个函数,使其使用起来更方便。使用window.scroll()甚至window.scrollBy()会更容易,因为我以前尝试过,但这两个有一些问题:

一切都变成垃圾后,使用他们与平稳的行为。 你无论如何都不能阻止他们,必须等到卷轴的结尾。 希望我的函数对你们有用。此外,还有一个轻量级的填充程序,可以在Safari甚至IE中运行。

下面是代码

照搬就行,想怎么搞就怎么搞。

import smoothscroll from 'smoothscroll-polyfill';

smoothscroll.polyfill();

const prepareSmoothScroll = linkEl => {
  const EXTRA_OFFSET = 0;

  const destinationEl = document.getElementById(linkEl.dataset.smoothScrollTo);
  const blockOption = linkEl.dataset.smoothScrollBlock || 'start';

  if ((blockOption === 'start' || blockOption === 'end') && EXTRA_OFFSET) {
    const anchorEl = document.createElement('div');

    destinationEl.setAttribute('style', 'position: relative;');
    anchorEl.setAttribute('style', `position: absolute; top: -${EXTRA_OFFSET}px; left: 0;`);

    destinationEl.appendChild(anchorEl);

    linkEl.addEventListener('click', () => {
      anchorEl.scrollIntoView({
        block: blockOption,
        behavior: 'smooth',
      });
    });
  }

  if (blockOption === 'center' || !EXTRA_OFFSET) {
    linkEl.addEventListener('click', () => {
      destinationEl.scrollIntoView({
        block: blockOption,
        behavior: 'smooth',
      });
    });
  }
};

export const activateSmoothScroll = () => {
  const linkEls = [...document.querySelectorAll('[data-smooth-scroll-to]')];

  linkEls.forEach(linkEl => prepareSmoothScroll(linkEl));
};

要创建一个link元素,只需添加以下data属性:

data-smooth-scroll-to="element-id"

还可以将另一个属性设置为加法

data-smooth-scroll-block="center"

它表示scrollIntoView()函数的块选项。默认为start。在MDN上阅读更多。

最后

根据您的需要调整平滑滚动功能。

例如,如果你有一些固定的标题(或者我用单词masthead来称呼它),你可以这样做:

const mastheadEl = document.querySelector(someMastheadSelector);

// and add it's height to the EXTRA_OFFSET variable

const EXTRA_OFFSET = mastheadEl.offsetHeight - 3;

如果你没有这样的情况,那就删除它,为什么不:-D。

其他回答

根据arsenie - ii的回答:我有一个用例,其中滚动实体不是窗口本身,而是一个内部模板(在这种情况下是div)。在这个场景中,我们需要为滚动容器设置一个ID,并通过getElementById获取它来使用它的滚动函数:

<div class="scroll-container" id="app-content">
  ...
</div>
const yOffsetForScroll = -100
const y = document.getElementById(this.idToScroll).getBoundingClientRect().top;
const main = document.getElementById('app-content');
main.scrollTo({
    top: y + main.scrollTop + yOffsetForScroll,
    behavior: 'smooth'
  });

把它留在这里,以防有人面临类似的情况!

另一个解决方案是使用"offsetTop",就像这样:

var elementPosition = document.getElementById('id').offsetTop;

window.scrollTo({
  top: elementPosition - 10, //add your necessary value
  behavior: "smooth"  //Smooth transition to roll
});

解决方案,如果你是使用离子电容器,角材料,并需要支持iOS 11。

                document.activeElement.parentElement.parentElement.scrollIntoView({block: 'center', behavior: 'smooth'}); 

关键是滚动到父节点的父节点,也就是输入的包装器。这个包装器包含输入的标签,该标签现在不再被切断。

如果你只需要支持iOS 14,“block”中心参数实际上是有效的,所以这是足够的:

                document.activeElement.scrollIntoView({block: 'center', behavior: 'smooth'}); 

我的主要想法是在我们想要滚动到的视图上方创建一个tempDiv。它在我的项目中工作得很好,没有滞后。

scrollToView = (element, offset) => {
    var rect = element.getBoundingClientRect();
    var targetY = rect.y + window.scrollY - offset;

    var tempDiv;
    tempDiv = document.getElementById("tempDiv");
    if (tempDiv) {
        tempDiv.style.top = targetY + "px";
    } else {
        tempDiv = document.createElement('div');
        tempDiv.id = "tempDiv";
        tempDiv.style.background = "#F00";
        tempDiv.style.width = "10px";
        tempDiv.style.height = "10px";
        tempDiv.style.position = "absolute";
        tempDiv.style.top = targetY + "px";
        document.body.appendChild(tempDiv);
    }

    tempDiv.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

示例使用

onContactUsClick = () => {
    this.scrollToView(document.getElementById("contact-us"), 48);
}

希望能有所帮助

你也可以使用element.scrollIntoView()选项

el.scrollIntoView(
  { 
    behavior: 'smooth', 
    block: 'start' 
  },
);

大多数浏览器都支持