ScrollIntoView () заставляет всю страницу перемещаться


110

Я использую 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, чтобы мы могли точно увидеть, в чем проблема?
Роберт Коритник

Ответы:


120

Вы можете использовать scrollTopвместо scrollIntoView():

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

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

Если вы хотите прокрутить более одного прокручиваемого элемента, вам нужно будет изменить scrollTopкаждый из них индивидуально в зависимости от offsetTopзначений s промежуточных элементов. Это должно дать вам детальный контроль, чтобы избежать возникшей у вас проблемы.

EDIT: offsetTop не обязательно относительно родительского элемента - он относительно первого позиционированного предка. Если родительский элемент не позиционирован (относительный, абсолютный или фиксированный), вам может потребоваться изменить вторую строку на:

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

4
К вашему сведению, это работает только тогда, когда родитель находится вверху страницы. Тебе, наверное, стоит это сделать,target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Фил

2
offsetTop определяется относительно ближайшего расположенного родителя, поэтому, если родительский узел имеет position: relative, вы не должны вычитать его смещение. Но в большинстве случаев вы правы.
Brilliand

2
Вот скрипт js: jsfiddle.net/LEqjm/258, который также показывает неправильное поведение ScrollIntoView.
Рафи

1
@Brilliand спасибо за идею о position: relativeprent div: это действительно решает проблему
Алекс Жуковский

Он работает с хромом, но немного больше прокручивается в IE, что скрывает текстовое содержимое сверху. Любое решение @Phil, Заранее спасибо
Сония

128

Исправлено:

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

см. https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
Спасибо, это сработало. Я не смог понять использование блока и его значений, когда прочитал его. Теперь, когда он решил проблему, я знаю, что он делает
Паван

3
Что значит «ближайший»? РЕДАКТИРОВАТЬ: нашел ответ здесь: stackoverflow.com/a/48635751/628418
Сэмми

Это решило мою проблему. Некоторое время я наблюдал, как это происходит в нашем веб-приложении, но было сложно заблокировать воспроизведение для этого. После добавления новой функции это происходило каждый раз, и я смог отследить это до этого вызова, в котором отсутствовал block : 'nearest'параметр.
roskelld

Если бы только они определили, что означают значения блоков .... начало и ближайший ... все это методом проб и ошибок.
Bae

Работает с Chrome, но не с Edge для меня.
Майкл

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

или вы можете использоватьtop: el['offsetTop']
Junior Mayhé

Это работает лучше всего для меня. Но все равно немного глючит в firefox - иногда останавливается на полпути к элементу. Прекрасная кромка и хром.
Марк

10

У меня тоже была эта проблема, и я потратил много часов, пытаясь с ней справиться. Я надеюсь, что мое решение все еще может помочь некоторым людям.

Мое исправление оказалось:

  • Для Chrome: изменение .scrollIntoView()на .scrollIntoView({block: 'nearest'})(спасибо @jfrohn).
  • Для Firefox: примените overflow: -moz-hidden-unscrollable;к элементу контейнера, который сдвигается.
  • Не тестировалось в других браузерах.

9

Поэкспериментируйте с scrollIntoViewIfNeeded()... убедитесь, что он поддерживается браузером.


1
Не знал, что это была вещь. Есть полифилл
mpen

В документе упоминается, что он нестандартный, но работает нормально. мы должны это использовать?
Шьям Кумар

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

в моем контексте он убирал липкую панель инструментов с экрана или вводил рядом с потрясающей кнопкой с абсолютом.

используя ближайший решенный.

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

1

У меня была та же проблема, я исправил ее, удалив transform:translateYCSS, который я разместил на footerстранице.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.