javascript window.scrollTo 的选项在 Microsoft Edge 上不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/52276194/
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
window.scrollTo with options not working on Microsoft Edge
提问by CDK
I have a strange issue which I can only replicate on Microsoft browsers (Edge and IE11 tested).
我有一个奇怪的问题,我只能在 Microsoft 浏览器上复制(Edge 和 IE11 测试)。
<style>
body {
height: 5000px;
width: 5000px;
}
</style>
<p>Click the button to scroll the document window to 1000 pixels.</p>
<button onclick="scrollWin()">Click me to scroll!</button>
<script>
function scrollWin() {
window.scrollTo({
left: 1000,
top: 1000,
behavior:"smooth"
});
}
</script>
This code correctly scrolls the window 1000px to the left and down, with a smooth behaviour in Chrome and Firefox. However, on Edge and IE, it does not move at all.
此代码正确地将窗口向左和向下滚动 1000 像素,在 Chrome 和 Firefox 中具有平滑的行为。但是,在 Edge 和 IE 上,它根本不动。
回答by eyecatchUp
As mentioned before, the Scroll Behavior specificationhas only been implemented in Chrome, Firefox and Opera.
如前所述,滚动行为规范仅在 Chrome、Firefox 和 Opera 中实现。
Here's a one-liner to detect support for the behaviorproperty in ScrollOptions:
这是检测对 中的behavior属性的支持的单行代码ScrollOptions:
const supportsNativeSmoothScroll = 'scrollBehavior' in document.documentElement.style;
And here's a simple implementation for cross-browser smooth scrolling: https://nicegist.github.io/d210786daa23fd57db59634dd231f341
这是跨浏览器平滑滚动的简单实现:https: //nicegist.github.io/d210786daa23fd57db59634dd231f341
回答by CDK
Maybe not a true answer in the sense of the word, but I have solved this problem by using this helpful polyfill: https://github.com/iamdustan/smoothscrollwhich works really well across all browsers.
从这个词的意义上来说,也许不是一个真正的答案,但我已经通过使用这个有用的 polyfill 解决了这个问题:https: //github.com/iamdustan/smoothscroll,它在所有浏览器上都运行良好。
Example page for pollyfill: http://iamdustan.com/smoothscroll/
pollyfill 的示例页面:http://iamdustan.com/smoothscroll/
Many thanks to the author.
非常感谢作者。
回答by Kaiido
Indeed, they don't support this variant, MDN articles should be updated.
确实,他们不支持这种变体,应该更新 MDN 文章。
One way to polyfill this method is to run the scrollmethod in a requestAnimationFramepowered loop. Nothing too fancy here.
填充此方法的一种方法是scroll在requestAnimationFrame动力循环中运行该方法。这里没有什么太花哨的。
The main problem that arises is how to detect when this variant is not supported.actually @nlawson's answertackles this problem perfectly...
出现的主要问题是如何检测何时不支持此变体。实际上@nlawson 的回答完美地解决了这个问题......
For this, we can use the fact that a call to Window#scrollwill fire a ScrollEventif the viewPort actually did scroll.
This means we can set up an asynchronous test that will:
为此,我们可以使用以下事实:如果 viewPort 确实滚动,则调用Window#scroll将触发ScrollEvent。
这意味着我们可以设置一个异步测试,它将:
- Attach an event handlerto the ScrollEvent,
- Call a first time
scroll(left , top)variant to be sure the Eventwill fire, - Overwrite this call with a second one using the optionsvariant.
- In the event handler, if we aren't at the correct scroll position, this means we need to attach our polyfill.
- 将事件处理程序附加到ScrollEvent,
- 调用第一个时间
scroll(left , top)变量以确保事件会触发, - 使用选项变体用第二个调用覆盖此调用。
- 在事件处理程序中,如果我们不在正确的滚动位置,这意味着我们需要附加我们的 polyfill。
So the caveat of this test is that it is an asynchronous test. But since you need to actually wait for the document has loaded before calling this method, I guess in 99% of cases it will be ok.
所以这个测试的警告是它是一个异步测试。但是由于您需要在调用此方法之前实际等待文档已加载,因此我想在 99% 的情况下都可以。
Now to less burden the main doc, and since it is already an asynchronous test, we can even wrap this test inside an iframe, which gives us something like:
现在为了减轻主文档的负担,并且由于它已经是一个异步测试,我们甚至可以将此测试包装在 iframe 中,这给了我们类似的东西:
/* Polyfills the Window#scroll(options) & Window#scrollTo(options) */
(function ScrollPolyfill() {
// The asynchronous tester
// wrapped in an iframe (will not work in SO's StackSnippet?)
var iframe = document.createElement('iframe');
iframe.onload = function() {
var win = iframe.contentWindow;
// listen for a scroll event
win.addEventListener('scroll', function handler(e){
// when the scroll event fires, check that we did move
if(win.pageXOffset < 99) { // !== 0 should be enough, but better be safe
attachPolyfill();
}
// cleanup
document.body.removeChild(iframe);
});
// set up our document so we can scroll
var body = win.document.body;
body.style.width = body.style.height = '1000px';
win.scrollTo(10, 0); // force the event
win.scrollTo({left:100, behavior:'instant'}); // the one we actually test
};
// prepare our frame
iframe.src = "about:blank";
iframe.setAttribute('width', 1);
iframe.setAttribute('height', 1);
iframe.setAttribute('style', 'position:absolute;z-index:-1');
iframe.onerror = function() {
console.error('failed to load the frame, try in jsfiddle');
};
document.body.appendChild(iframe);
// The Polyfill
function attachPolyfill() {
var original = window.scroll, // keep the original method around
animating = false, // will keep our timer's id
dx = 0,
dy = 0,
target = null;
// override our methods
window.scrollTo = window.scroll = function polyfilledScroll(user_opts) {
// if we are already smooth scrolling, we need to stop the previous one
// whatever the current arguments are
if(animating) {
clearAnimationFrame(animating);
}
// not the object syntax, use the default
if(arguments.length === 2) {
return original.apply(this, arguments);
}
if(!user_opts || typeof user_opts !== 'object') {
throw new TypeError("value can't be converted to a dictionnary");
}
// create a clone to not mess the passed object
// and set missing entries
var opts = {
left: ('left' in user_opts) ? user_opts.left : window.pageXOffset,
top: ('top' in user_opts) ? user_opts.top : window.pageYOffset,
behavior: ('behavior' in user_opts) ? user_opts.behavior : 'auto',
};
if(opts.behavior !== 'instant' && opts.behavior !== 'smooth') {
// parse 'auto' based on CSS computed value of 'smooth-behavior' property
// But note that if the browser doesn't support this variant
// There are good chances it doesn't support the CSS property either...
opts.behavior = window.getComputedStyle(document.scrollingElement || document.body)
.getPropertyValue('scroll-behavior') === 'smooth' ?
'smooth' : 'instant';
}
if(opts.behavior === 'instant') {
// not smooth, just default to the original after parsing the oject
return original.call(this, opts.left, opts.top);
}
// update our direction
dx = (opts.left - window.pageXOffset) || 0;
dy = (opts.top - window.pageYOffset) || 0;
// going nowhere
if(!dx && !dy) {
return;
}
// save passed arguments
target = opts;
// save the rAF id
animating = anim();
};
// the animation loop
function anim() {
var freq = 16 / 300, // whole anim duration is approximately 300ms @60fps
posX, poxY;
if( // we already reached our goal on this axis ?
(dx <= 0 && window.pageXOffset <= +target.left) ||
(dx >= 0 && window.pageXOffset >= +target.left)
){
posX = +target.left;
}
else {
posX = window.pageXOffset + (dx * freq);
}
if(
(dy <= 0 && window.pageYOffset <= +target.top) ||
(dy >= 0 && window.pageYOffset >= +target.top)
){
posY = +target.top;
}
else {
posY = window.pageYOffset + (dx * freq);
}
// move to the new position
original.call(window, posX, posY);
// while we are not ok on both axis
if(posX !== +target.left || posY !== +target.top) {
requestAnimationFrame(anim);
}
else {
animating = false;
}
}
}
})();
Sorry for not providing a runable demo inside the answer directly, but StackSnippet?'s over-protected iframes don't allow us to access the content of an inner iframe on IE...
So instead, here is a link to a jsfiddle.
抱歉没有直接在答案中提供可运行的演示,但是 StackSnippet? 的过度保护的 iframe 不允许我们访问 IE 上内部 iframe 的内容......
所以相反,这里有一个指向jsfiddle的链接。
Post-scriptum:Now comes to my mind that it might actually be possible to check for support in a synchronous way by checking for the CSS scroll-behaviorsupport, but I'm not sure it really covers all UAs in the history...
Post-scriptum:现在我想到实际上可以通过检查 CSSscroll-behavior支持以同步方式检查支持,但我不确定它是否真的涵盖了历史上的所有 UA...
Post-Post-scriptum:Using @nlawson's detection we can now have a working snippet ;-)
Post-Post-scriptum:使用@nlawson 的检测,我们现在可以有一个工作片段;-)
/* Polyfills the Window#scroll(options) & Window#scrollTo(options) */
(function ScrollPolyfill() {
// The synchronous tester from @nlawson's answer
var supports = false
test_el = document.createElement('div'),
test_opts = {top:0};
// ES5 style for IE
Object.defineProperty(test_opts, 'behavior', {
get: function() {
supports = true;
}
});
try {
test_el.scrollTo(test_opts);
}catch(e){};
if(!supports) {
attachPolyfill();
}
function attachPolyfill() {
var original = window.scroll, // keep the original method around
animating = false, // will keep our timer's id
dx = 0,
dy = 0,
target = null;
// override our methods
window.scrollTo = window.scroll = function polyfilledScroll(user_opts) {
// if we are already smooth scrolling, we need to stop the previous one
// whatever the current arguments are
if(animating) {
clearAnimationFrame(animating);
}
// not the object syntax, use the default
if(arguments.length === 2) {
return original.apply(this, arguments);
}
if(!user_opts || typeof user_opts !== 'object') {
throw new TypeError("value can't be converted to a dictionnary");
}
// create a clone to not mess the passed object
// and set missing entries
var opts = {
left: ('left' in user_opts) ? user_opts.left : window.pageXOffset,
top: ('top' in user_opts) ? user_opts.top : window.pageYOffset,
behavior: ('behavior' in user_opts) ? user_opts.behavior : 'auto',
};
if(opts.behavior !== 'instant' && opts.behavior !== 'smooth') {
// parse 'auto' based on CSS computed value of 'smooth-behavior' property
// But note that if the browser doesn't support this variant
// There are good chances it doesn't support the CSS property either...
opts.behavior = window.getComputedStyle(document.scrollingElement || document.body)
.getPropertyValue('scroll-behavior') === 'smooth' ?
'smooth' : 'instant';
}
if(opts.behavior === 'instant') {
// not smooth, just default to the original after parsing the oject
return original.call(this, opts.left, opts.top);
}
// update our direction
dx = (opts.left - window.pageXOffset) || 0;
dy = (opts.top - window.pageYOffset) || 0;
// going nowhere
if(!dx && !dy) {
return;
}
// save passed arguments
target = opts;
// save the rAF id
animating = anim();
};
// the animation loop
function anim() {
var freq = 16 / 300, // whole anim duration is approximately 300ms @60fps
posX, poxY;
if( // we already reached our goal on this axis ?
(dx <= 0 && window.pageXOffset <= +target.left) ||
(dx >= 0 && window.pageXOffset >= +target.left)
){
posX = +target.left;
}
else {
posX = window.pageXOffset + (dx * freq);
}
if(
(dy <= 0 && window.pageYOffset <= +target.top) ||
(dy >= 0 && window.pageYOffset >= +target.top)
){
posY = +target.top;
}
else {
posY = window.pageYOffset + (dx * freq);
}
// move to the new position
original.call(window, posX, posY);
// while we are not ok on both axis
if(posX !== +target.left || posY !== +target.top) {
requestAnimationFrame(anim);
}
else {
animating = false;
}
}
}
})();
// OP's code,
// by the time you click the button, the polyfill should already be set up if needed
function scrollWin() {
window.scrollTo({
left: 1000,
top: 1000,
behavior: 'smooth'
});
}
body {
height: 5000px;
width: 5000px;
}
<p>Click the button to scroll the document window to 1000 pixels.</p>
<button onclick="scrollWin()">Click me to scroll!</button>
回答by nlawson
You can detect support for the behavioroption in scrollTousing this snippet:
您可以使用此代码段检测对该behavior选项的支持scrollTo:
function testSupportsSmoothScroll () {
var supports = false
try {
var div = document.createElement('div')
div.scrollTo({
top: 0,
get behavior () {
supports = true
return 'smooth'
}
})
} catch (err) {}
return supports
}
Tested in Chrome, Firefox, Safari, and Edge, and seems to work correctly. If supportsis false, you fall back to a polyfill.
在 Chrome、Firefox、Safari 和 Edge 中测试,似乎可以正常工作。如果supports为 false,则返回到 polyfill。
回答by Lazar Nikolic
Unfortunately, there is no way for that method to work in these two browsers. You can check open issues here and see that they have done nothing on this issue. https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/15534521/
不幸的是,该方法无法在这两种浏览器中工作。您可以在此处检查未解决的问题,并查看他们在此问题上没有做任何事情。 https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/15534521/
回答by Deepak-MSFT
You can try to use Element.ScrollLeft and Element.ScrollTop property with Window.scrollTo().
您可以尝试将 Element.ScrollLeft 和 Element.ScrollTop 属性与 Window.scrollTo() 一起使用。
Below is the example which is working with Edge and other browsers.
下面是使用 Edge 和其他浏览器的示例。
<html>
<style>
body {
height: 5000px;
width: 5000px;
}
</style>
<p>Click the button to scroll the document window to 1000 pixels.</p>
<button onclick="scrollWin(this)">Click me to scroll!</button>
<script>
function scrollWin(pos) {
window.scrollTo(pos.offsetTop+1000,pos.offsetLeft+1000);
}
</script>
</html>
Smooth behavior is not working with this code.
平滑行为不适用于此代码。
Reference:
参考:
Regards
问候
Deepak
迪帕克

