70

是否可以使用平滑滚动来锚定链接但没有 jQuery?我正在创建一个新站点,但我不想使用jQuery.

4

17 回答 17

60

扩展这个答案:https ://stackoverflow.com/a/8918062/3851798

定义你的scrollTo函数后,你可以在函数中传递你想要scrollTo的元素。

function scrollTo(element, to, duration) {
    if (duration <= 0) return;
    var difference = to - element.scrollTop;
    var perTick = difference / duration * 10;

    setTimeout(function() {
        element.scrollTop = element.scrollTop + perTick;
        if (element.scrollTop === to) return;
        scrollTo(element, to, duration - 10);
    }, 10);
}

如果你有一个 id="footer" 的 div

<div id="footer" class="categories">…&lt;/div>

在您运行滚动的脚本中,您可以运行它,

elmnt = document.getElementById("footer");
scrollTo(document.body, elmnt.offsetTop, 600);

你有它。没有 jQuery 的平滑滚动。您实际上可以在浏览器的控制台上使用该代码并根据自己的喜好对其进行微调。

于 2015-08-13T11:45:58.470 回答
48

使用此处的函数:JavaScript 动画并对其进行修改以修改属性(不仅是样式的属性),您可以尝试以下操作:

演示:http: //jsfiddle.net/7TAa2/1/

只是说...

function animate(elem, style, unit, from, to, time, prop) {
  if (!elem) {
    return;
  }
  var start = new Date().getTime(),
    timer = setInterval(function() {
      var step = Math.min(1, (new Date().getTime() - start) / time);
      if (prop) {
        elem[style] = (from + step * (to - from)) + unit;
      } else {
        elem.style[style] = (from + step * (to - from)) + unit;
      }
      if (step === 1) {
        clearInterval(timer);
      }
    }, 25);
  if (prop) {
    elem[style] = from + unit;
  } else {
    elem.style[style] = from + unit;
  }
}

window.onload = function() {
  var target = document.getElementById("div5");
  animate(document.scrollingElement || document.documentElement, "scrollTop", "", 0, target.offsetTop, 2000, true);
};
div {
  height: 50px;
}
<div id="div1">asdf1</div>
<div id="div2">asdf2</div>
<div id="div3">asdf3</div>
<div id="div4">asdf4</div>
<div id="div5">asdf5</div>
<div id="div6">asdf6</div>
<div id="div7">asdf7</div>
<div id="div8">asdf8</div>
<div id="div9">asdf9</div>
<div id="div10">asdf10</div>
<div id="div10">asdf11</div>
<div id="div10">asdf12</div>
<div id="div10">asdf13</div>
<div id="div10">asdf14</div>
<div id="div10">asdf15</div>
<div id="div10">asdf16</div>
<div id="div10">asdf17</div>
<div id="div10">asdf18</div>
<div id="div10">asdf19</div>
<div id="div10">asdf20</div>

于 2013-07-18T20:31:48.307 回答
44

实际上,有更轻量级和简单的方法可以做到这一点: https ://codepen.io/ugg0t/pen/mqBBBY

function scrollTo(element) {
  window.scroll({
    behavior: 'smooth',
    left: 0,
    top: element.offsetTop
  });
}

document.getElementById("button").addEventListener('click', () => {
  scrollTo(document.getElementById("8"));
});
div {
  width: 100%;
  height: 200px;
  background-color: black;
}

div:nth-child(odd) {
  background-color: white;
}

button {
  position: absolute;
  left: 10px;
  top: 10px;
}
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<div id="4"></div>
<div id="5"></div>
<div id="6"></div>
<div id="7"></div>
<div id="8"></div>
<div id="9"></div>
<div id="10"></div>
<button id="button">Button</button>

于 2017-11-16T05:03:29.743 回答
8

用这个:

let element = document.getElementById("box");

element.scrollIntoView();
element.scrollIntoView(false);
element.scrollIntoView({block: "end"});
element.scrollIntoView({behavior: "instant", block: "end", inline: "nearest"});

演示https ://jsfiddle.net/anderpo/x8ucc5ak/1/

于 2018-01-30T09:31:44.327 回答
4

带有:target选择器的 CSS3 过渡可以在没有任何 JS 黑客攻击的情况下提供很好的结果。我只是在考虑是否要实现这一点,但如果没有 Jquery,它确实会有点混乱。有关详细信息,请参阅此问题

于 2014-04-30T14:59:09.260 回答
4

这是一个很老的问题,但我认为现在 CSS 支持平滑滚动很重要,因此不需要任何脚本:

html {
  scroll-behavior: smooth;
}

截至 2019 年,此属性仍然不支持 Safari 或 IE/Edge,因此要获得完整的跨浏览器支持,您仍然必须使用脚本。

于 2019-12-09T14:19:48.137 回答
4

Vanilla js 变体使用requestAnimationFrame缓动和支持的所有浏览器:

const requestAnimationFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame;

function scrollTo(to) {
    const start = window.scrollY || window.pageYOffset
    const time = Date.now()
    const duration = Math.abs(start - to) / 3;

    (function step() {
        var dx = Math.min(1, (Date.now() - time) / duration)
        var pos = start + (to - start) * easeOutQuart(dx)

        window.scrollTo(0, pos)

        if (dx < 1) {
            requestAnimationFrame(step)
        }
    })()
}

支持任何动!

于 2019-03-03T16:55:41.637 回答
4

在这里试试这个代码:

window.scrollTo({
        top: 0,
        left: 0,
        behavior: 'smooth'
    });
于 2019-05-10T16:12:43.420 回答
4

使用 polyfill 平滑滚动行为...

例子:

document.querySelectorAll('a[href^="#"]').addEventListener("click", function(event) {
  event.preventDefault();
  document.querySelector(this.getAttribute("href")).scrollIntoView({ behavior: "smooth" });
});

存储库:https ://github.com/iamdustan/smoothscroll

于 2018-07-15T23:48:57.793 回答
3

我目前最喜欢的滚动到库是Zenscroll,因为它功能广泛且体积小(目前只有 3.17kb)。

将来使用本机功能可能更有意义scrollIntoView,但由于缺乏 IE 支持,现在大多数生产站点都必须对它进行 polyfill,我建议在所有情况下都使用 Zenscroll。

于 2018-02-21T12:32:45.817 回答
1

基于滚动选项的MDN 文档,我们可以使用以下代码:

element.scrollTo({
  top: 100,
  left: 100,
  behavior: 'smooth'
});

事实上,behaviorkey 可以接受smoothauto变量。第一个用于平滑运动,第二个用于单跳。‍‍</p>

于 2020-02-23T08:35:22.767 回答
1

这是@Ian 的升级版

// Animated scroll with pure JS
// duration constant in ms
const animationDuration = 600;
// scrollable layout
const layout = document.querySelector('main');
const fps = 12;  // in ms per scroll step, less value - smoother animation
function scrollAnimate(elem, style, unit, from, to, time, prop) {
    if (!elem) {
        return;
    }
    var start = new Date().getTime(),
        timer = setInterval(function () {
            var step = Math.min(1, (new Date().getTime() - start) / time);
            var value =  (from + step * (to - from)) + unit;
            if (prop) {
                elem[style] = value;
            } else {
                elem.style[style] = value;
            }
            if (step === 1) {
                clearInterval(timer);
            }
        }, fps);
    if (prop) {
        elem[style] = from + unit;
    } else {
        elem.style[style] = from + unit;
    }
}

function scrollTo(hash) {
    const target = document.getElementById(hash);
    const from = window.location.hash.substring(1) || 'start';
    const offsetFrom = document.getElementById(from).offsetTop;
    const offsetTo = target.offsetTop;
    scrollAnimate(layout,
        "scrollTop", "", offsetFrom, offsetTo, animationDuration, true);
    setTimeout(function () {
      window.location.hash = hash;
    }, animationDuration+25)
};

// add scroll when click on menu items 
var menu_items = document.querySelectorAll('a.mdl-navigation__link');
menu_items.forEach(function (elem) {
    elem.addEventListener("click",
        function (e) {
            e.preventDefault();
            scrollTo(elem.getAttribute('href').substring(1));
        });
});

// scroll when open link with anchor 
window.onload = function () {
    if (window.location.hash) {
        var target = document.getElementById(window.location.hash.substring(1));
        scrollAnimate(layout, "scrollTop", "", 0, target.offsetTop, animationDuration, true);
    }
}
于 2019-02-20T00:16:02.173 回答
1

对于 2019 年的任何人,首先,您添加一个事件侦听器

  document.getElementById('id').addEventListener('click', () => scrollTo())

然后你以元素为目标并顺利进行

function scrollTo() {
    let target = document.getElementById('target');
    target.scrollIntoView({
        behavior: "smooth", 
        block: "end", 
        inline: "nearest"
    })
}
于 2019-05-16T18:03:20.590 回答
0

有关平滑滚动的更全面的方法列表,请参阅我的答案here


要在准确的时间内滚动到某个位置,window.requestAnimationFrame可以使用,每次计算出合适的当前位置。不支持setTimeout时可以使用类似的效果。requestAnimationFrame

/*
   @param pos: the y-position to scroll to (in pixels)
   @param time: the exact amount of time the scrolling will take (in milliseconds)
*/
function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

演示:

function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

document.getElementById("toElement").addEventListener('click', function(e) {
  var elem = document.querySelector("div");
  scrollToSmoothly(elem.offsetTop);
});
document.getElementById("toTop").addEventListener('click', function(e){
  scrollToSmoothly(0, 700);
});
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="toTop">Scroll back to top</button>
</div>

对于更复杂的情况,可以使用SmoothScroll.js 库,它可以处理垂直和水平平滑滚动、在其他容器元素内滚动、不同的缓动行为、从当前位置相对滚动等等。

document.getElementById("toElement").addEventListener('click', function(e) {
  smoothScroll({toElement: document.querySelector('div'), duration: 500});
});
document.getElementById("toTop").addEventListener('click', function(e){
  smoothScroll({yPos: 0, duration: 700});
});
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/SmoothScroll@1.2.0/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="toTop">Scroll back to top</button>
</div>

或者,您可以传递一个选项对象,window.scroll该对象滚动到特定的 x 和 y 位置,并window.scrollBy从当前位置滚动一定量:

// Scroll to specific values
// scrollTo is the same
window.scroll({
  top: 2500, 
  left: 0, 
  behavior: 'smooth' 
});

// Scroll certain amounts from current position 
window.scrollBy({ 
  top: 100, // could be negative value
  left: 0, 
  behavior: 'smooth' 
});

演示:

<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scroll({
      top: elem.offsetTop, 
      left: 0, 
      behavior: 'smooth' 
});
}
</script>

现代浏览器支持scroll-behaviorCSS 属性,该属性可用于使文档中的滚动平滑(无需 JavaScript)。锚标签可以通过给锚标签 ahref加上要滚动#id的元素来使用)。您还可以为scroll-behavior特定容器设置属性,如 adiv以使其内容平滑滚动。

html, body{
  scroll-behavior: smooth;
}
<a href="#elem">Scroll To Element</a>
<div id="elem" style="margin: 500px 0px;">Div</div>

于 2021-08-03T16:46:49.577 回答
0

如果您想将所有深层链接设置#为平滑滚动,您可以这样做:

const allLinks = document.querySelectorAll('a[href^="#"]')
allLinks.forEach(link => {

  const 
    targetSelector = link.getAttribute('href'),
    target = document.querySelector(targetSelector)

  if (target) {
    link.addEventListener('click', function(e) {

    e.preventDefault()

    const top = target.offsetTop // consider decreasing your main nav's height from this number

    window.scroll({
      behavior: 'smooth',
      left: 0,
      top: top
    });

  })
}
})

一个示例代码也可以考虑您的主导航的高度(此代码top位于声明 const 的位置):

const 
  mainHeader = document.querySelector('header#masthead'), //change to your correct main nav selector
  mainHeaderHeight = mainHeader.offsetHeight,
  // now calculate top like this:
  top = target.offsetTop - mainHeaderHeight 
于 2022-01-21T11:24:00.477 回答
0

这是纯 JavaScript的简单解决方案。它利用了 CSS 属性scroll-behavior: smooth

function scroll_to(id) {       
    document.documentElement.style.scrollBehavior = 'smooth'
    element = document.createElement('a');
    element.setAttribute('href', id)
    element.click();
}

用法

假设我们有 10 个 div:

<div id='df7ds89' class='my_div'>ONE</div>
<div id='sdofo8f' class='my_div'>TWO</div>
<div id='34kj434' class='my_div'>THREE</div>
<div id='gbgfh98' class='my_div'>FOUR</div>
<div id='df89sdd' class='my_div'>FIVE</div>
<div id='34l3j3r' class='my_div'>SIX</div>
<div id='56j5453' class='my_div'>SEVEN</div>
<div id='75j6h4r' class='my_div'>EIGHT</div>
<div id='657kh54' class='my_div'>NINE</div>
<div id='43kjhjh' class='my_div'>TEN</div>

我们可以滚动到选择的 ID

scroll_to('#657kh54')

您只需在单击事件上调用此函数(例如单击按钮然后滚动到 div #9)。

结果

在此处输入图像描述

当然,它在现实生活中看起来要流畅得多。

小提琴

不幸的是,截至2019 年,IE 和 Safari 不支持 scrollBehavior = 'smooth'

在此处输入图像描述 MDN 网络文档

于 2019-02-26T20:59:05.207 回答
0

没有jQuery

const links = document.querySelectorAll('header nav ul a')

for (const link of links) {
  link.onclick = function clickHandler(e) {
    e.preventDefault()
    const href = this.getAttribute('href')
    document.querySelector(href).scrollIntoView({ behavior: 'smooth' })
  }
}
  body {
    background-color: black;
    height:7000px
  }

  header {
    margin-top: 1.3rem;
    margin-bottom: 25rem;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  nav ul {
    display: flex;
  }

  nav ul li {
    all: unset;
    margin: 2rem;
    cursor: pointer;
  }

  nav ul li a {
    all: unset;
    font: bold 1.8rem robto;
    color: white;
    letter-spacing: 1px;
    cursor: pointer;
    padding-top: 3rem;
    padding-bottom: 2rem;
  }

  #team,
  #contact,
  #about {
    background-color: #e2df0d;
    width: 100%;
    height: 35rem;
    display: flex;
    justify-content: center;
    align-items: center;
    color: black;
    font: bold 4rem roboto;
    letter-spacing: 6.2px;
    margin-top: 70rem;

  }
<header>
  <!-- NavBar -->
  <nav>
    <ul>
      <li><a href="#team">Team</a></li>
      <li><a href="#contact">Contact</a></li>
      <li><a href="#about">About</a></li>
    </ul>
  </nav>
</header>

<!-- ----------- Team ----------------------- -->
<div id="team">
  <h2>Team</h2>
</div>

<!-- ----------- Contact ----------------------- -->
<div id="contact">
  <h2>Contact</h2>
</div>

<!-- ----------- About ----------------------- -->
<div id="about">
  <h2>About</h2>
</div>

或仅使用CSS,但尚不支持所有浏览器

html {scroll-behavior: smooth}

于 2021-09-23T13:59:31.100 回答