简体   繁体   English

ScrollIntoView() 导致整个页面移动

[英]ScrollIntoView() causing the whole page to move

I am using ScrollIntoView() to scroll the highlighted item in a list into view.我正在使用 ScrollIntoView() 将列表中突出显示的项目滚动到视图中。 When I scroll downwards ScrollIntoView(false) works perfectly.当我向下滚动时, ScrollIntoView(false) 工作得很好。 But when I scroll upwards, ScrollIntoView(true) is causing the whole page to move a little which I think is intended.但是当我向上滚动时, ScrollIntoView(true) 会导致整个页面移动一点,我认为这是有意的。 Is there a way to avoid the whole page move when using ScrollIntoView(true)?使用 ScrollIntoView(true) 时有没有办法避免整个页面移动?

Here is the structure of my page -这是我页面的结构 -

#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 is coming from ajax call. listOfDivs 来自 ajax 调用。 Using mobile safari.使用移动 Safari。

Fixed it with:修复它:

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

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

You could use scrollTop instead of scrollIntoView() :您可以使用scrollTop而不是scrollIntoView()

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

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

If there's more than one scrollable element that you want to scroll, you'll need to change the scrollTop of each one individually, based on the offsetTop s of the intervening elements.如果要滚动多个可滚动元素,则需要根据中间元素的offsetTop分别更改每个元素的scrollTop This should give you the fine-grained control to avoid the problem you're having.这应该为您提供细粒度的控制,以避免您遇到的问题。

EDIT: offsetTop isn't necessarily relative to the parent element - it's relative to the first positioned ancestor.编辑: offsetTop 不一定相对于父元素 - 它是相对于第一个定位的祖先。 If the parent element isn't positioned (relative, absolute or fixed), you may need to change the second line to:如果父元素未定位(相对、绝对或固定),您可能需要将第二行更改为:

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

I had this problem too, and spent many hours trying to deal with it.我也遇到了这个问题,花了很多时间来解决它。 I hope my resolution may still help some people.我希望我的决议仍然可以帮助一些人。

My fix ended up being:我的修复最终是:

  • For Chrome: changing .scrollIntoView() to .scrollIntoView({block: 'nearest'}) (thanks to @jfrohn).对于 Chrome:将.scrollIntoView()更改为.scrollIntoView({block: 'nearest'}) (感谢@jfrohn)。
  • For Firefox: apply overflow: -moz-hidden-unscrollable;对于 Firefox:应用overflow: -moz-hidden-unscrollable; on the container element that shifts.在移动的容器元素上。
  • Not tested in other browsers.未在其他浏览器中测试。

使用scrollIntoViewIfNeeded() ...确保浏览器支持它。

in my context, he would push the sticky toolbar off the screen, or enter next to a fab button with absolute.在我的上下文中,他会将粘性工具栏从屏幕上推开,或者在绝对按钮旁边输入。

using the nearest solved.使用最近求解。

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

I've added a way to display the imporper behavior of the ScrollIntoView - http://jsfiddle.net/LEqjm/258/ [it should be a comment but I don't have enough reputation]我添加了一种方法来显示 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);
    }
});

jQuery plugin scrollintoview() increases usability jQuery 插件scrollintoview()增加了可用性

Instead of default DOM implementation you can use a plugin that animates movement and doesn't have any unwanted effects.除了默认的 DOM 实现之外,您还可以使用动画移动并且没有任何不需要的效果的插件。 Here's the simplest way of using it with defaults:这是使用默认值的最简单方法:

$("yourTargetLiSelector").scrollintoview();

Anyway head over to this blog post where you can read all the details and will eventually get you to GitHub source code of the plugin.无论如何,请访问此博客文章,您可以在其中阅读所有详细信息,并最终将您带到该插件的GitHub 源代码

This plugin automatically searches for the closest scrollable ancestor element and scrolls it so that selected element is inside its visible view port.该插件会自动搜索最近的可滚动祖先元素并滚动它,以便选定元素位于其可见视口内。 If the element is already in the view port it doesn't do anything of course.如果元素已经在视口中,它当然不会做任何事情。

Adding more information to @Jesco post.@Jesco帖子中添加更多信息。

  • Element.scrollIntoViewIfNeeded() non-standard WebKit method for Chrome, Opera, Safari browsers. Element.scrollIntoViewIfNeeded()适用于 Chrome、Opera、Safari 浏览器non-standard WebKit method
    If the element is already within the visible area of the browser window, then no scrolling takes place .如果元素已经在浏览器窗口的可见区域内,则不会发生滚动
  • Element.scrollIntoView() method scrolls the element on which it's called into the visible area of the browser window. Element.scrollIntoView()方法将调用它的元素滚动到浏览器窗口的可见区域。

Try the below code in mozilla.org scrollIntoView() link.mozilla.org scrollIntoView()链接中尝试以下代码。 Post to identify Browser发布以识别浏览器

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

Just to add an answer as per my latest experience and working on VueJs.只是根据我的最新经验和在 VueJs 上的工作添加一个答案。 I found below piece of code ad best, which does not impact your application in anyways.我发现下面的代码广告最好,无论如何它不会影响您的应用程序。

const el = this.$el.getElementsByClassName('your_element_class')[0];
if (el) {
   scrollIntoView(el,
                  {
                       block: 'nearest',
                       inline: 'start',
                       behavior: 'smooth',
                       boundary: document.getElementsByClassName('main_app_class')[0]
                    });
     }

main_app_class is the root class main_app_class是根类

your_element_class is the element/view where you can to scroll into your_element_class是您可以滚动到的元素/视图

And for browser which does not support ScrollIntoView() just use below library its awesome https://www.npmjs.com/package/scroll-into-view-if-needed对于不支持 ScrollIntoView() 的浏览器,只需使用下面的库,它的真棒https://www.npmjs.com/package/scroll-into-view-if-needed

Using Brilliant's idea, here's a solution that only (vertically) scrolls if the element is NOT currently visible.使用 Brilliant 的想法,这是一个仅在元素当前不可见时才(垂直)滚动的解决方案。 The idea is to get the bounding box of the viewport and the element to be displayed in browser-window coordinate space.这个想法是获取视口的边界框和要在浏览器窗口坐标空间中显示的元素。 Check if it's visible and if not, scroll by the required distance so the element is shown at the top or bottom of the viewport.检查它是否可见,如果不可见,则滚动所需的距离,以便元素显示在视口的顶部或底部。

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

我遇到了同样的问题,我通过删除放置在页面页footertransform:translateY CSS 来修复它。

ScrollIntoView() causes page movement. ScrollIntoView() 导致页面移动。 But the following code works fine for me and move the screen to the top of the element:但是下面的代码对我来说很好,并将屏幕移动到元素的顶部:

window.scroll({
  top: document.getElementById('your-element')?.offsetParent.offsetTop,
  behavior: 'smooth',
  block: 'start',
})

FWIW: I found (in Chrome 95, and Firefox 92 (all Mac)) that using: FWIW:我发现(在 Chrome 95 和 Firefox 92(所有 Mac)中)使用:

.scrollIntoView({ behavior:'smooth', block:'center'}); .scrollIntoView({ behavior:'smooth', block:'center'});

on a scrollable list of options would scroll the body element a little, so I opted to use:在可滚动的选项列表上会稍微滚动一下 body 元素,所以我选择使用:

.scrollIntoView({ behavior:'smooth', block:'nearest'}); .scrollIntoView({ behavior:'smooth', block:'nearest'});

and select an option past the one I wanted centered (eg in a scrollable elem with 5 lines/options viewable, I selected the 2nd option past the one I wanted centered, thereby centering the desired element.并选择一个超过我想要居中的选项(例如,在一个可滚动的元素中,可以查看 5 行/选项,我选择了第二个选项,超过了我想要居中的那个,从而使所需元素居中。

在此处输入图像描述

I found (in Chrome) I could more reliably scroll my element to the top of my parent div (without moving the page) if I scrolled from the bottom up to my element rather than from the top down to my element.我发现(在 Chrome 中)如果我从底部向上滚动到我的元素而不是从顶部向下滚动到我的元素,我可以更可靠地将我的元素滚动到我的父 div 的顶部(不移动页面)。 Otherwise while my element would scroll into view, it would sometimes still be lower than desired within the div.否则,虽然我的元素会滚动到视图中,但有时它仍会低于 div 中的预期值。

To achieve this, I am scrolling in two steps:为此,我分两步滚动:

  1. myScrollableDiv.scrollTop = myScrollableDiv.scrollHeight which instantly scrolls to the bottom of my scrollable div myScrollableDiv.scrollTop = myScrollableDiv.scrollHeight立即滚动到我的可滚动 div 的底部
  2. (as per other answers here) Scroll my the element into view with animation: (根据此处的其他答案)使用动画将我的元素滚动到视图中:
myElementWithinTheScrollingDiv.scrollIntoView({
  behavior: 'smooth',
  block: 'nearest',
})

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

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