Skip to content

Исправлена прокрутка к якорю во встроенном содержимом - #625

Open
villanella wants to merge 1 commit into
DocHubTeam:v3.15.1from
villanella:fix/anchor-link-navigation
Open

villanella wants to merge 1 commit into
DocHubTeam:v3.15.1from
villanella:fix/anchor-link-navigation

Conversation

@villanella

@villanella villanella commented Sep 20, 2026

Copy link
Copy Markdown

Проблема

Переход по прямой ссылке с якорем, например .../entities/<сущность>/blank?<параметры>#some.anchor.id и клик по ссылке на якорь на этой же странице, открывают страницу с начала, а не нужный раздел, если якорь находится во встроенном содержимом. Только после нескольких обновлений страницы переход срабатывает. Встроенное содержимое - это вложенные документы (@document/...) и презентации сущностей (@entity/...) - например, сущности-требования, подключенные в ADR. Якорь может быть написан вручную в тексте или создан mustache-шаблоном, это не важно.

Причина

  1. scrollBehavior всегда вызывал window.scrollTo(0, 0) и не учитывал to.hash.
  2. Встроенное содержимое загружается уже после того, как маршрут разрешился, и якоря в нём ещё нет. Одной проверки наличия элемента недостаточно.
  3. Если промис из scrollBehavior вернуть с false, vue-router 3 прокручивает страницу к позиции, сохранённой при старте навигации. При загрузке страница навигируется несколько раз, и устаревшие позиции затирают правильную прокрутку.

Шаги воспроизведения

  1. Открыть страницу с встроенной сущностью и якорем, находящимся ближе к концу страницы, например, id сущности вида #some.anchor.id.
  2. Скопировать URL вместе с якорем #some.anchor.id.
  3. Открыть его в новой вкладке. Страница остаётся в начале или останавливается выше якоря.

Что изменено

Изменён только src/frontend/router/index.js:

  • Якорь ищется через document.getElementById. Это безопасно для id с точками, в отличие от CSS-селектора.
  • Поиск идёт опросом каждые 200 мс до 30 секунд. MutationObserver не использован: при частой перерисовке DOM он подвешивал страницу.
  • Прокрутка повторяется, пока положение элемента не перестанет меняться. Содержимое выше элемента может догружаться ещё несколько секунд.
  • Промис возвращает текущую позицию прокрутки, а не false.
  • Новый переход с якорем останавливает предыдущий цикл опроса.
  • Переходы без якоря работают как раньше: страница прокручивается в начало.

Тест

anchor-demo.zip - в данном тестовом архиве корневой манифест root.yaml локально подключает docs.yaml. В проекте три документа: главный документ встраивает два вложенных, в каждом есть якорь ![](@anchor/...). Якорь второго документа находится ниже первого экрана.

Запуск: скопировать папку anchor-demo в public/workspace/ репозитория DocHub и выполнить

VUE_APP_DOCHUB_ROOT_MANIFEST=workspace/anchor-demo/root.yaml VUE_APP_DOCHUB_ROOT_DOCUMENT=demo.main npm run serve

Для режима с backend заменить serve на backend. Подробности в README.md архива.

Проверка:

  1. Открыть /docs/demo.main#demo.part2.anchor в новой вкладке.
  2. Открыть /docs/demo.main и кликнуть по ссылке part 2 вверху страницы.

Результат (Chrome, окно 1280x800, npm run serve):

Открытие URL с якорем Клик по ссылке
До правки страница в начале (scrollY 0, якорь на 2116) страница в начале
После правки scrollY 2116 scrollY 2116

С правкой в режиме npm run backend результат тот же. Ссылка на первый якорь ведёт себя так же (якорь на 306). Числа зависят от размера окна.

Дополнительно проверен переход с другой страницы: клик по ссылке /docs/demo.main#demo.part2.anchor или /entities/docs/blank?dh-doc-id=demo.main#demo.part2.anchor с другой страницы. До правки страница оставалась в начале, после правки прокручивается к якорю.

Также проверено на большом проекте с реальными данными (закрытый репозиторий) в режимах npm run serve и npm run backend: scrollY совпадает с положением якоря при холодной загрузке (переход по URL с якорем) и при переходе с одного якоря на другой, а открытие без якоря показывает начало страницы.

Связанное

Коммит 6184a83 из v3.15.1, связанный с issue #539, сохраняет якорь в адресе ссылки при клике, но не обеспечивает прокрутку к якорю во встроенном содержимом. Эта правка добавляет такую прокрутку, в том числе при переходе с другой страницы.

scrollBehavior always scrolled to the top and ignored to.hash, so a URL
with an anchor opened at the top of the page. The content loads after
the route is resolved, so the element often does not exist yet.

Now the element is looked up by id every 200 ms, for up to 30 s. It is
scrolled into view again while its position keeps changing, because
content above it can still grow.

The promise resolves with the current scroll position, not with false.
With false, vue-router scrolls back to the position saved before the
navigation, and the page moved away from the anchor. A newer navigation
to an anchor stops the previous polling.
@villanella villanella changed the title Wait for the target element before scrolling to an anchor Исправлен переход по якорным ссылкам при прямом открытии URL Sep 20, 2026
@villanella villanella changed the title Исправлен переход по якорным ссылкам при прямом открытии URL Исправлен переход по якорным ссылкам во встроенном содержимом Sep 20, 2026
@villanella villanella changed the title Исправлен переход по якорным ссылкам во встроенном содержимом Исправлен переход по URL с якорной ссылкой во встроенном содержимом Sep 20, 2026
@villanella villanella changed the title Исправлен переход по URL с якорной ссылкой во встроенном содержимом Исправлена прокрутка к якорю во встроенном содержимом Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant