Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Событие по изменению содержания страницы (https://javascript.ru/forum/dom-window/85558-sobytie-po-izmeneniyu-soderzhaniya-stranicy.html)

Юра_2310 20.10.2023 12:37

Событие по изменению содержания страницы
 
Не нашел события, чтобы отследить завершение размещения в DOM изменений на странице в "одностраничном" приложении. То есть при нажатии кнопки функция JS загружает на уже открытую страницу новое содержание. После загрузки надо прокрутить скролл в определенное положение. Если сразу прокрутить (window.scrollTo(0, 6000) или document.documentElement.scrollTop=6000) - выполняет прокрутку примерно на 2/3 от нужной. Небольшие странички работают значительно лучше.
Пробовал подключить событие readystatechange. Но оно не реагирует, т.е. не замечает изменения состояния, всегда "complete". Т.е. загрузка на страницу нового содержания в моем случае не вызывает это событие.
Как решать эту проблему?

Nexus 20.10.2023 12:50

Изменить скрипт, который модифицирует содержимое страницы таким образом, чтобы он генерировал событие в конце своего "жизненного процесса", либо повесить на страницу MutationObserver и слушать все изменения на странице до тех пор, пока они не прекратятся на какое-то время.

Первый вариант предпочтительнее, второй - при безвыходности.

Aetae 20.10.2023 12:51

Нет таких событий, потому что все SPA - это просто работа с DOM, никак не связанная с жизненным циклом страницы с точки зрения браузера.

Все SPA фреймворки позволяют тем или иным образом отслеживать отрисовку компонентов в DOM, собственно с этой стороны и надо походить если хотите чистого и правильного кода. Если вы пользуетесь самописной какашкой - то, как и советуют выше, допишите в неё такую возможность.

Если же хотите накостылять, то можно использовать MutationObsrver или\и ResizeObserver для того чтобы следить "снаружи".

voraa 20.10.2023 13:08

После загрузки все изменения в DOM выполняются в одном обработчике, который нельзя прервать какими то событиями. Попробуйте выполнять прокрутку в следующем событии от таймера
setTimeout (() => document.documentElement.scrollTop=6000, 0)

Юра_2310 20.10.2023 15:18

Спасибо всем за помощь!
Вариант с setTimeout вполне подошел.
Работает даже задержкой в 1 (о, чудо!): setTimeout(restorePosition, 1);

Правда функцию restorePosition (в которой document.documentElement.scrollTop), сделал асинхронной.
Костыли в виде MutationObsrver или\и ResizeObserver как-то не стал пробовать.

SPA фреймворки - не мое. Импорта замещение (свои какашки) как-то лучше. Просто предпочитаю чистый и правильный код.

voraa 20.10.2023 16:51

Цитата:

Сообщение от Юра_2310
Правда функцию restorePosition (в которой document.documentElement.scrollTop), сделал асинхронной.

Какой смысл?
Асинхронная отличается от обычной только тем, что в ней можно await использовать и всегда возвращает промис.

Юра_2310 20.10.2023 17:04

Цитата:

Сообщение от voraa (Сообщение 553688)
Какой смысл?
Асинхронная отличается от обычной только тем, что в ней можно await использовать и всегда возвращает промис.

Да, так и написано в учебнике. Еще я слышал, что она работает как бы параллельно, после того как завершится синхронный код. Точно, конечно, не могу сказать.
Но в моем случае не асинхронная - не работает. Только если async.
Еще добавлю, что сама эта асинхронная функция тоже не срабатывала. А вот запуск ее через setTimeout решил проблему. Чудеса, правда?

voraa 20.10.2023 17:24

В js, кроме worker ничего не работает параллельно, все работает в одном потоке
Цитата:

Сообщение от Юра_2310
Но в моем случае не асинхронная - не работает. Только если async.

Не видя функции ничего нельзя сказать. Если она только вызывается в setTimeout, то ей должно быть абсолютно все равно, объявлена она асинхронной или нет. Весь смыл асинхронной функции, что она вернет промис, который будет разрешен, когда выполнятся какие то асинхронные операции внутри нее. Если там нет асинхронных операций (await), и ничего не возвращает, то она просто вернет Promise.resolve(undefined).

Юра_2310 21.10.2023 04:31

Цитата:

Сообщение от voraa (Сообщение 553691)
Не видя функции ничего нельзя сказать.

Вот та функция. Убрал асинхронность. На самом деле работает также. Очевидно, где-то ошибся вначале.

function restorePosition(){
document.documentElement.scrollTop = 6000;
}

Сразу после копирования изменений в DOM:
setTimeout(restorePosition, 0);

Без таймера прокручивает до значения где-то около 4000. Не ожидал такого от таймера. Еще раз спасибо!
Можно ли так сказать, что таймер выдернул функцию из очереди на выполнение и выполнил ее после того как эта очередь освободилась, раз все работает в одном потоке?

voraa 21.10.2023 08:48

setTimeout ставит функцию в очередь через указанный интервал.


Часовой пояс GMT +3, время: 20:30.