Javascript - window.scroll({ behavior: 'smooth' }) 在 Safari 中不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51229742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:27:37  来源:igfitidea点击:

Javascript - window.scroll({ behavior: 'smooth' }) not working in Safari

javascriptsafari

提问by Sorakthun Ly

As the title says, it works perfectly fine on Chrome. But in Safari, it just sets the page to the desired top and and left position. Is this an expected behaviour? Is there a way to make it work nicely?

正如标题所说,它在 Chrome 上运行良好。但在 Safari 中,它只是将页面设置到所需的顶部和左侧位置。这是预期的行为吗?有没有办法让它很好地工作?

采纳答案by George Daniel

Behavior options aren't fully supported in IE/Edge/Safari, so you'd have to implement something on your own. I believe jQuery has something already, but if you're not using jQuery, here's a pure JavaScript implementation:

IE/Edge/Safari 并不完全支持行为选项,因此您必须自己实现一些东西。我相信 jQuery 已经有了一些东西,但如果你不使用 jQuery,这里有一个纯 JavaScript 实现:

function SmoothVerticalScrolling(e, time, where) {
    var eTop = e.getBoundingClientRect().top;
    var eAmt = eTop / 100;
    var curTime = 0;
    while (curTime <= time) {
        window.setTimeout(SVS_B, curTime, eAmt, where);
        curTime += time / 100;
    }
}

function SVS_B(eAmt, where) {
    if(where == "center" || where == "")
        window.scrollBy(0, eAmt / 2);
    if (where == "top")
        window.scrollBy(0, eAmt);
}

And if you need horizontal scrolling:

如果您需要水平滚动:

function SmoothHorizontalScrolling(e, time, amount, start) {
    var eAmt = amount / 100;
    var curTime = 0;
    var scrollCounter = 0;
    while (curTime <= time) {
        window.setTimeout(SHS_B, curTime, e, scrollCounter, eAmt, start);
        curTime += time / 100;
        scrollCounter++;
    }
}

function SHS_B(e, sc, eAmt, start) {
    e.scrollLeft = (eAmt * sc) + start;
}

And an example call is:

一个示例调用是:

SmoothVerticalScrolling(myelement, 275, "center");

回答by Eugen Sunic

Use smootscroll polyfill(solution for all browsers), easy applicable and lightweight dependency: https://github.com/iamdustan/smoothscroll

使用smootscroll polyfill(适用于所有浏览器的解决方案),易于应用和轻量级依赖:https: //github.com/iamdustan/smoothscroll

Once you install it via npm or yarn, add it to your main.js, .tsfile (one which executes first)

通过 npm 或 yarn 安装后,将其添加到.js、.ts文件(首先执行的文件)

import smoothscroll from 'smoothscroll-polyfill';
// or if linting/typescript complains
import * as smoothscroll from 'smoothscroll-polyfill';

// kick off the polyfill!
smoothscroll.polyfill();

回答by T. Dayya

The solution with the smoothest performance, especially if you want to incorporate easing is to use requestAnimationFrame:

性能最流畅的解决方案,特别是如果你想合并缓动是使用 requestAnimationFrame:

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

const step = (timestamp) => {
  window.scrollBy(
    0,
    1, // or whatever INTEGER you want (this controls the speed)
  );

  requestAnimationFrame(step);
};


requestAnimationFrame(step);

if you want to later cancel the scroll, you need to have a reference to your requestAnimationFrame (do this everywhere you use requestAnimationFrame(step)):

如果你想稍后取消滚动,你需要引用你的 requestAnimationFrame(在你使用 requestAnimationFrame(step) 的任何地方都这样做):

this.myRequestAnimationFrame = requestAnimationFrame(step);

const cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
cancelAnimationFrame(this.myRequestAnimationFrame);


Now what if you want to use easing with your scroll and take timeouts between scroll actions?

现在,如果您想对滚动使用缓动并在滚动操作之间超时怎么办?

create an array of 60 elements (requestAnimationFrame usually calls 60 times per second. It's technically whatever the refresh rate of the browser is, but 60 is the most common number.) We are going to fill this array non-linearly then use those numbers to control how much to scroll at each step of requestAnimationFrame:

创建一个包含 60 个元素的数组(requestAnimationFrame 通常每秒调用 60 次。从技术上讲,无论浏览器的刷新率是多少,但 60 是最常见的数字。)我们将非线性地填充这个数组,然后使用这些数字来控制 requestAnimationFrame 的每一步滚动多少:

let easingPoints = new Array(60).fill(0)

choose an easing function. Let's say we're doing a cubic ease-out:

选择缓动函数。假设我们正在做三次缓出:

function easeCubicOut(t) {
    return --t * t * t + 1;
}

create a dummy array and fill it with data piped through the easing function. You'll see why we need this in a moment:

创建一个虚拟数组并用通过缓动函数管道传输的数据填充它。你马上就会明白为什么我们需要这个:

    // easing function will take care of decrementing t at each call (too lazy to test it at the moment. If it doesn't, just pass it a decrementing value at each call)
    let t = 60;
    const dummyPoints = new Array(60).fill(0).map(()=> easeCubicOut(t));
    const dummyPointsSum = dummyPoints.reduce((a, el) => {
                                a += el;
                               return a;
                           }, 0);

map easingPoints using the help of each dummyPoint ratio to dummyPointsSum:

使用每个 dummyPoint 比率将 easingPoints 映射到 dummyPointsSum:

    easingPoints = easingPoints.map((el, i) => {
        return Math.round(MY_SCROLL_DISTANCE * dummyPoints[i] / dummyPointsSum);
    });

in your scroll function, we'll make a few adjustments:

在您的滚动功能中,我们将进行一些调整:

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

     let i = 0;
     const step = (timestamp) => {
       window.scrollBy(
         0,
         easingPoints[i],
       );


        if (++i === 60) {
                i = 0;
                return setTimeout(() => {
                  this.myRequestAnimationFrame = requestAnimationFrame(step);
                }, YOUR_TIMEOUT_HERE);
        }
      };


      this.myRequestAnimationFrame = requestAnimationFrame(step);

回答by Connor Cowling

A simple jQuery fix that works for Safari:

适用于 Safari 的简单 jQuery 修复:

$('a[href*="#"]').not('[href="#"]').not('[href="#0"]').click(function (t) {
    if (location.pathname.replace(/^\//, "") == this.pathname.replace(/^\//, "") && location.hostname == this.hostname) {
        var e = $(this.hash);
        e = e.length ? e : $("[name=" + this.hash.slice(1) + "]"), e.length && (t.preventDefault(), $("html, body").animate({
            scrollTop: e.offset().top
        }, 600, function () {
            var t = $(e);
            if (t.focus(), t.is(":focus")) return !1;
            t.attr("tabindex", "-1"), t.focus()
        }))
    }
});