ScrollIntoView () призводить до переміщення всієї сторінки


110

Я використовую ScrollIntoView () для прокрутки виділеного елемента в списку, який переглядається. Коли я прокручую вниз, ScrollIntoView (помилково) працює чудово. Але коли я прокручую вгору, ScrollIntoView (true) змушує всю сторінку трохи переміститися, що, на мою думку, призначене. Чи є спосіб уникнути переміщення всієї сторінки при використанні ScrollIntoView (вірно)?

Ось структура моєї сторінки -

#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, щоб ми могли точно бачити, у чому проблема?
Роберт Коритник

Відповіді:


115

Ви можете використовувати scrollTopзамість scrollIntoView():

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

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

Якщо ви хочете прокрутити більше одного елемента, який потрібно прокручувати, вам потрібно буде змінити scrollTopкожен окремо на основі offsetTops втручаються елементів. Це повинно дати вам тонкий дрібний контроль, щоб уникнути проблеми, яка виникає.

EDIT: offsetTop не обов'язково стосується батьківського елемента - це відносно першого позиціонованого предка. Якщо батьківський елемент не розташований (відносний, абсолютний чи фіксований), можливо, вам знадобиться змінити другий рядок на:

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

3
FYI, це працює лише тоді, коли батьків знаходиться вгорі сторінки. Ви, мабуть, мали б це зробитиtarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil

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

2
Ось js-скрипка: jsfiddle.net/LEqjm/258, яка також показує неправильну поведінку ScrollIntoView.
Рафі

1
@Brilliand дякую за ідею про position: relativeпрент дів: це дійсно виправить проблему
Олексій Жуковський

Він працює над хромом, але трохи прокручує IE, який приховує текстовий вміст зверху. Будь-яке рішення @Phil, заздалегідь дякую
Сонія

123

Виправлено це за допомогою:

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

дивіться: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


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

3
Що означає "найближчий"? EDIT: Тут знайдено відповідь: stackoverflow.com/a/48635751/628418
Sammi

Це вирішило мою проблему. Я спостерігаю, як це трапляється в нашому веб-додатку, але важко заблокувати запит на це. Після додавання нової функції це відбувалося щоразу, і мені вдалося простежити це за цим дзвінком, на якому не вистачало 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 - іноді він зупиняє частину шляху до стихії. Тонка по краю і хрому.
Марк

9

У мене теж була ця проблема, і я багато годин намагався впоратися з нею. Я сподіваюся, що моя резолюція все-таки може допомогти деяким людям.

Моє виправлення закінчилося:

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

8

Пограйте з scrollIntoViewIfNeeded()… переконайтесь, що браузер підтримує його.


1
Не знав, що це річ. Там в polyfill
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: Це, звичайно, правда, але це не означає, що вони не використовують його або не хочуть його використовувати. Все, що я роблю, - це надання альтернативи. Це на ОП, щоб вирішити, чи буде це шлях чи ні. Можливо, вони ніколи не думали використовувати jQuery в першу чергу.
Роберт Коритник

Про те, що ОП спеціально не згадував jQuery, абсолютно не має значення: @ Відповідь Роберта Корітника мені прекрасно послужила.
Дейв Ленд

1
Між іншим, Бінг показує зразок коду в результатах пошуку для "утримуйте елемент предка від прокручування за допомогою 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'
});

1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.