简体   繁体   English

平滑滚动锚链接没有 jQuery

[英]Smooth scroll anchor links WITHOUT jQuery

Is it possible to use smooth scroll to anchor links but without jQuery ?是否可以使用平滑滚动来锚定链接但没有jQuery I am creating a new site and I don't want to use jQuery .我正在创建一个新站点,我不想使用jQuery

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

After defining your function of scrollTo, you can pass the element you want to scrollTo in the function.定义好你的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);
}

If you have a div with an id="footer"如果你有一个 id="footer" 的 div

<div id="footer" class="categories">…</div>

In the script that you run to scroll you can run this,在您运行滚动的脚本中,您可以运行它,

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

And there you have it.你有它。 Smooth scrolling without jQuery.没有 jQuery 的平滑滚动。 You can actually play around with that code on your browser's console and fine tune it to your liking.您实际上可以在浏览器的控制台上使用该代码并根据自己的喜好对其进行微调。

Using the function from here: JavaScript animation and modifying it to modify a property (not only a style's property), you can try something like this:使用此处的函数: JavaScript animation并修改它以修改属性(不仅仅是样式的属性),您可以尝试以下操作:

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

Just saying...就是说...

 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>

Actually, there is more lightweight and simple way to do that: https://codepen.io/ugg0t/pen/mqBBBY实际上,有更轻量级和简单的方法来做到这一点: 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>

Use this:用这个:

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

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

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

CSS3 transitions with a :target selector can give a nice result without any JS hacking.带有:target选择器的 CSS3 转换可以在没有任何 JS hack 的情况下提供不错的结果。 I was just contemplating whether to imlement this but without Jquery it does get a bit messy.我只是在考虑是否要实现这一点,但没有 Jquery,它确实有点混乱。 See this question for details.有关详细信息,请参阅此问题

Smooth Scroll behavior with polyfill...使用 polyfill 平滑滚动行为...

Example:例子:

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

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

Vanilla js variant using requestAnimationFrame with easings and all browsers supported:使用带有缓动和所有浏览器的requestAnimationFrame Vanilla js 变体:

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)
        }
    })()
}

Any easing supported!支持任何缓动

Try this code here:在这里试试这个代码:

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

This is a pretty old question, but I think it's important to say that nowadays smooth scrolling is supported in CSS, so there's no need for any scripts:这是一个很老的问题,但我认为重要的是现在 CSS 支持平滑滚动,因此不需要任何脚本:

html {
  scroll-behavior: smooth;
}

This property still has no support for Safari or IE/Edge as of 2019, so for a full crossbrowser support, you'll still have to use a script.截至 2019 年,此属性仍然不支持 Safari 或 IE/Edge,因此要获得完整的跨浏览器支持,您仍然必须使用脚本。

纯轻量级的JavaScript库: 在github上顺畅滚动

My favorite scroll-to library currently is Zenscroll because of the wide range of features and small size (currently only 3.17kb).我目前最喜欢的滚动到库是Zenscroll,因为它具有广泛的功能和小尺寸(目前只有 3.17kb)。

In the future it may make more sense to use the native scrollIntoView functionality, but since it'd have to be polyfilled in most production sites today due to the lack of IE support, I recommend using Zenscroll instead in all cases.将来,使用原生scrollIntoView功能可能更有意义,但是由于缺乏 IE 支持,现在大多数生产站点都必须对它进行 polyfill,因此我建议在所有情况下都使用 Zenscroll。

March 2022 2022 年 3 月

I know this is an old question but wanted to put forward an answer that has simpler ways of doing it in modern days.我知道这是一个老问题,但想提出一个在现代有更简单方法的答案。 As of today, almost all the major browsers are compatible with scroll-behavior including Safari with its latest release.截至今天,几乎所有主流浏览器都与scroll-behavior兼容,包括最新版本的 Safari。 Still, you might want to employ fallback methods or just use the javascript approach described in method 2 for compatibility in older browsers.不过,您可能希望使用回退方法或仅使用方法 2 中描述的 javascript 方法,以便在旧浏览器中兼容。

Method 1: HTML and CSS方法一:HTML 和 CSS

You can just do this with你可以这样做

<a href="#target" id="scroll-trigger">Click</a>
.
.
.
<h2 id="target">Target</h2>

and CSS和 CSS

html {
    scroll-behavior: smooth
} 

Method 2: JavaScript方法二:JavaScript

Or if you have a unique case that needs javascript, go on elaborate with this method.或者,如果您有一个需要 javascript、go 的独特案例,请使用此方法进行详细说明。

const scrollTrigger = document.getElementById('scroll-trigger');
const target = document.getElementById('target');

scrollTrigger.addEventListener('click', function (e) {
    window.scroll({
        top: target.offsetTop,
        left:0,
        behavior: 'smooth' });
}, false)

It's upgraded version from @Ian这是@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);
    }
}

For anyone in 2019, first, you add an event listener对于 2019 年的任何人,首先,您添加一个事件侦听器

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

then you target the element and go smoothly to it然后你瞄准这个元素并顺利地找到它

function scrollTo() {
    let target = document.getElementById('target');
    target.scrollIntoView({
        behavior: "smooth", 
        block: "end", 
        inline: "nearest"
    })
}

Based on MDN docs for scroll options we can use the following code:基于MDN 文档的滚动选项,我们可以使用以下代码:

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

In fact, the behavior key can accept smooth and auto variables.事实上, behavior键可以接受smoothauto变量。 first for smooth motion and second for a single jump.首先是平滑运动,其次是单次跳跃。 ‍‍ ‍‍

Here is a simple solution in pure JavaScript .这是纯 JavaScript 的一个简单解决方案。 It takes advantage of CSS property scroll-behavior: smooth它利用了 CSS 属性scroll-behavior: smooth

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

Usage :用法

Say we have 10 divs:假设我们有 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>

We can scroll to the ID of choice :我们可以滚动到选择的 ID

scroll_to('#657kh54')

You simply call this function on your click event (eg click button then scroll to div #9).您只需在单击事件上调用此函数(例如单击按钮然后滚动到 div #9)。

Result :结果

在此处输入图片说明

Of course it looks much smoother in real life.当然,它在现实生活中看起来要流畅得多。

FIDDLE小提琴

Unfortunately, IE and Safari don't support scrollBehavior = 'smooth' as of 2019不幸的是,截至2019 年,IE 和 Safari 不支持 scrollBehavior = 'smooth'

在此处输入图片说明 MDN Web Docs MDN 网络文档

For a more comprehensive list of methods for smooth scrolling, see my answer here .对于用于平滑滚动的方法更全面的列表,请参阅我的答案在这里


To scroll to a certain position in an exact amount of time, window.requestAnimationFrame can be put to use, calculating the appropriate current position each time.要在精确的时间内滚动到某个位置,可以使用window.requestAnimationFrame ,每次计算适当的当前位置。 setTimeout can be used to a similar effect when requestAnimationFrame is not supported.当不支持requestAnimationFrame时,可以使用setTimeout达到类似的效果。

/*
   @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);
        }
    });
}

Demo:演示:

 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>

For more complex cases, the SmoothScroll.js library can be used, which handles smooth scrolling both vertically and horizontally, scrolling inside other container elements, different easing behaviors, scrolling relatively from the current position, and more.对于更复杂的情况,可以使用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>

Alternatively, you can pass an options object to window.scroll which scrolls to a specific x and y position and window.scrollBy which scrolls a certain amount from the current position:或者,您可以将选项对象传递给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' 
});

Demo:演示:

 <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>

Modern browsers support the scroll-behavior CSS property , which can be used to make scrolling in the document smooth (without the need for JavaScript).现代浏览器支持scroll-behavior CSS 属性,可用于使文档中的滚动平滑(无需 JavaScript)。 Anchor tags can be used for this by giving the anchor tag a href of # plus the id of the element to scroll to).锚标签可用于此目的,方法是为锚标签提供#href加上要滚动到的元素的id )。 You can also set the scroll-behavior property for a specific container like a div to make its contents scroll smoothly.您还可以为特定容器(如div设置scroll-behavior属性,以使其内容平滑滚动。

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

Without jQuery没有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>

Or with just CSS , but it's not supported in all browsers yet或仅使用CSS ,但尚不支持所有浏览器

html {scroll-behavior: smooth}

If you want to set all of your deep links # to scroll smoothly you can do this:如果您想将所有深层链接设置为平滑滚动#您可以这样做:

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

  })
}
})

An example code to consider also your main nav's height (this code goes where top const is declared):一个示例代码也要考虑您的主导航的高度(此代码位于声明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 

Here is the most elegant and concise solution.这是最优雅和简洁的解决方案。

Links:链接:

<a href="#elementIDtoScrollTo"></a>

CSS: CSS:

html {
    scroll-behavior: smooth;
}

Remember to add a unique id="elementIDtoScrollTo" to each HTML element.请记住为每个 HTML 元素添加一个唯一的id="elementIDtoScrollTo"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM