ScrollIntoView()导致整个页面移动


109

我正在使用ScrollIntoView()将列表中突出显示的项目滚动到视图中。当我向下滚动时,ScrollIntoView(false)可以正常工作。但是,当我向上滚动时,ScrollIntoView(true)会使整个页面略微移动,这是我认为想要的。使用ScrollIntoView(true)时,是否有办法避免整个页面移动?

这是我页面的结构-

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs来自ajax调用。使用移动浏览器。

谢谢您的帮助!


1
您能否提供一个JSFiddle,以便我们确切地了解问题所在?
罗伯特·科里特尼克

Answers:


115

您可以使用scrollTop代替scrollIntoView()

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle:http : //jsfiddle.net/LEqjm/

如果要滚动的滚动元素不止一个,则需要scrollTop根据offsetTop中间元素的s 分别更改每个滚动元素的。这应该为您提供细粒度的控制,以避免出现问题。

编辑:offsetTop不一定相对于父元素-它相对于第一个定位的祖先。如果父元素未定位(相对,绝对或固定),则可能需要将第二行更改为:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;

3
仅供参考,这仅在父级位于页面顶部时才有效。您可能应该做到了target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil

2
offsetTop相对于最接近的父对象,因此,如果父节点具有position: relative,则不应减去其偏移量。但是在大多数情况下,您是对的。
Brilliand13年

2
这是一个js小提琴:jsfiddle.net/LEqjm/258,它还显示ScrollIntoView的不当行为。
拉菲,

1
@Brilliand感谢您提出关于prent position: relativediv的想法:它确实解决了问题
Alex Zhukovskiy

它在chrome上运行,但在IE上滚动的更多,这从顶部隐藏了文本内容。任何解决方案@Phil,在此先感谢
Soniya

120

使用以下方法修复了该问题:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

参见:https : //developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
谢谢你的工作。读取块时,我无法理解其用途。现在,它解决了一个问题,我知道它在做什么
Pavan

3
“最近”是什么意思?编辑:在这里找到答案:stackoverflow.com/a/48635751/628418
Sammi

这解决了我的问题。我已经在我们的Web应用程序中看到这种情况发生了一段时间,但是很难为它锁定repro。添加新功能后,它每次都会发生,我能够将其跟踪到此调用,而该调用缺少block : 'nearest'参数。
roskelld

如果它们定义了块值的含义,则...开始和最接近...所有的尝试和错误。

适用于Chrome,但不适用于Edge。
迈克尔

13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});

或者您也可以使用top: el['offsetTop']
JuniorMayhé18年

这对我来说是最好的。但是在firefox上仍然有一些小问题-有时它会在到元素的途中停止。边缘和镀铬精细。
马克

9

我也遇到了这个问题,花了很多时间试图解决这个问题。我希望我的决议仍然可以对某些人有所帮助。

我的修复最终是:

  • 对于Chrome:更改.scrollIntoView().scrollIntoView({block: 'nearest'})(感谢@jfrohn)。
  • 对于Firefox:overflow: -moz-hidden-unscrollable;在移动的容器元素上应用。
  • 未经其他浏览器测试。


8

我添加了一种方法来显示ScrollIntoView的不良行为-http: //jsfiddle.net/LEqjm/258/ [这应该是评论,但我没有足够的声誉]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});

7
不是jQuery问题。
seangates

6

jQuery插件 scrollintoview()提高了可用性

除了使用默认的DOM实现之外,您还可以使用为运动设置动画并且没有任何不良影响的插件。这是将其与默认值一起使用的最简单方法:

$("yourTargetLiSelector").scrollintoview();

无论如何,请转到此博客文章,您可以在其中阅读所有详细信息,并最终将您带到该插件的GitHub源代码

该插件自动搜索最接近的可滚动祖先元素并对其进行滚动,以使所选元素位于其可见视口内。如果元素已经在视口中,则它当然不会做任何事情。


19
@Brilliand:的确如此,但这并不意味着他们没有使用它或不愿意使用它。我正在做的就是提供替代方案。由OP决定这是否是他们要走的路。也许他们从来没有考虑过使用jQuery。
罗伯特·科里特尼克

OP没有特别提到jQuery是完全不相关的:@RobertKoritnik的回答对我非常有用。
戴夫·兰德

1
顺便说一句,Bing在搜索结果中显示了代码示例,以“保持祖先元素不会通过scrollintoview滚动”。:-)
戴夫·兰德

2

使用Brilliant的想法,这是一个解决方案,如果元素当前不可见,则仅(垂直)滚动。这个想法是获得视口的边界框和要在浏览器窗口坐标空间中显示的元素。检查它是否可见,如果不可见,请滚动所需的距离,以便将元素显示在视口的顶部或底部。

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }

2

添加更多信息以@Jesco发布。

  • Element.scrollIntoViewIfNeeded() non-standard WebKit method适用于Chrome,Opera,Safari浏览器。
    如果该元素已经在浏览器窗口的可见区域内,则不会发生滚动
  • Element.scrollIntoView() 方法将调用该元素的元素滚动到浏览器窗口的可见区域。

mozilla.org scrollIntoView()链接中尝试以下代码。发布以识别浏览器

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}

2

在我看来,他可以将粘性工具栏推离屏幕,或者在fab按钮旁边输入绝对值。

使用最近的解决方法。

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.