首页 > 解决方案 > 平滑滚动,跨浏览器,无需 jQuery

问题描述

您将在下面找到我为在单击本地链接时平滑滚动而创建的脚本。它是通过transform(没有jQuery)完成的。正如所见,我已经使用内联 CSS外部样式表实现了它。我推荐内联版本,因为可能很难猜测相关样式表的索引。

然而,问题在于滚动条的实际移动是在应用转换之后发生的。因此,如果您在滚动转换完成之前单击链接,则代码行为异常。

关于解决这个问题的任何想法?


编辑:

我知道那里有jQuery 解决方案第三方 polyfill 库。然而,我的目标是用普通的 JavaScript重新创建jQuery功能。


我的脚本:

// Get style rule's declaration block
function getStyleDeclaration(styleSheet, selectorText) {
  const rules = styleSheet.cssRules;
  return Array.from(rules).find(r => r.selectorText === selectorText).style;
  // for (let i = 0; i < rules.length; i += 1) {
  //   if (rules[i].selectorText === selectorText) return rules[i].style;
  // }
}

// Get specific style sheet, based on its title
// Many style sheets do not have a title however
// Which is main reason it is preferred to work with
// inline styles instead
function getStyleSheet(title) {
  const styleSheets = document.styleSheets;
  return Array.from(styleSheets).find(s => s.title === title);
  // for (let i = 0; i < styleSheets.length; i += 1) {
  //   if (styleSheets[i].title === title) return styleSheets[i];
  // }
}

function scrollToElement_ExternalStyleSheet(anchor, target) {
  anchor.addEventListener("click", e => {
    e.preventDefault();

    const time = 1000;
    // Distance from viewport to topof target
    const distance = -target.getBoundingClientRect().top;

    // Modify external style sheet
    const transStyle = getStyleDeclaration(document.styleSheets[1], ".trans");
    transStyle.transform = "translate(0, " + distance + "px)";
    transStyle.transition = "transform " + time + "ms ease";

    const root = document.documentElement; // <html> element
    root.classList.add("trans");

    window.setTimeout(() => {
      root.classList.remove("trans");
      root.scrollTo(0, -distance + window.pageYOffset);
    }, time);
  });
}

function scrollToElement_InlineStyle(anchor, target) {
  const root = document.documentElement;
  anchor.addEventListener('click', e => {
    e.preventDefault();

    const time = 900;
    const distance = -target.getBoundingClientRect().top;

    root.style.transform = 'translate(0, ' + distance + 'px)';
    root.style.transition = 'transform ' + time + 'ms ease';

    window.setTimeout(() => {
      root.scrollTo(0, -distance + window.pageYOffset);
      root.style.transform = null; // Revert to default
      root.style.transition = null;
    }, time);
  });
}

function applySmoothScroll() {
  const anchors = document.querySelectorAll("a");
  const localAnchors = Array.from(anchors).filter(
    a => a.getAttribute("href").indexOf("#") != -1
  );
  localAnchors.forEach(a => {
    const targetString = a.getAttribute("href");
    const target = document.querySelector(targetString);
    // scrollToElement_ExternalStyleSheet(a, target);
    scrollToElement_InlineStyle(a, target);
  });
}

applySmoothScroll();
.box {
  padding-bottom: 300px;
  padding-top: 0.5rem;
  background-color: orange;
  text-align: center;
  font-size: 200%;
}

.box:nth-child(even) {
  background-color: lightblue;
  color: white;
}

a {
  color: black;
}

body {
  margin: 0;
}

.trans {
  transform: translate(0, -100px);
  transition: transform 900ms ease;
}
<div id="s0" class="box"><a href="#s1">Click Me!</a></div>
<div id="s1" class="box"><a href="#s2">Click Me!</a></div>
<div id="s2" class="box"><a href="#s0">Click Me!</a></div>

标签: javascriptjqueryhtmlcss

解决方案


推荐阅读