fix: Prevent initial unnecessary IntersectionObserver callback execution (#2523)

This commit is contained in:
Luffy 2025-01-06 11:43:40 +08:00 committed by GitHub
parent 58268632c8
commit a73e07eac0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 14 deletions

View File

@ -45,7 +45,7 @@ export function Events(Base) {
// =========================================================================
/**
* Initialize cover observer
* Toggles sticky behavior when when cover is not in view
* Toggles sticky behavior when cover is not in view
* @void
*/
#initCover() {
@ -74,11 +74,17 @@ export function Events(Base) {
#initHeadings() {
const headingElms = dom.findAll('#main :where(h1, h2, h3, h4, h5)');
const headingsInView = new Set();
let isInitialLoad = true;
// Mark sidebar active item on heading intersection
this.#intersectionObserver?.disconnect();
this.#intersectionObserver = new IntersectionObserver(
entries => {
if (isInitialLoad) {
isInitialLoad = false;
return;
}
if (this.#isScrolling) {
return;
}
@ -89,18 +95,25 @@ export function Events(Base) {
headingsInView[op](entry.target);
}
const activeHeading =
headingsInView.size > 1
? // Sort headings by proximity to viewport top and select first
Array.from(headingsInView).sort((a, b) =>
a.compareDocumentPosition(b) &
Node.DOCUMENT_POSITION_FOLLOWING
? -1
: 1,
)[0]
: // Get first and only item in set.
// May be undefined if no headings are in view.
headingsInView.values().next().value;
let activeHeading;
if (headingsInView.size === 1) {
// Get first and only item in set.
// May be undefined if no headings are in view.
activeHeading = headingsInView.values().next().value;
} else if (headingsInView.size > 1) {
// Find the closest heading to the top of the viewport
// Reduce over the Set of headings currently in view (headingsInView) to determine the closest heading.
activeHeading = Array.from(headingsInView).reduce(
(closest, current) => {
return !closest ||
closest.compareDocumentPosition(current) &
Node.DOCUMENT_POSITION_FOLLOWING
? current
: closest;
},
null,
);
}
if (activeHeading) {
const id = activeHeading.getAttribute('id');

View File

@ -181,7 +181,7 @@ export class Compiler {
}
/**
* Compile sidebar, it uses _sidebar.md ( or specific file) or the content's headings toc to render sidebar.
* Compile sidebar, it uses _sidebar.md (or specific file) or the content's headings toc to render sidebar.
* @param {String} text Text content from the sidebar file, maybe empty
* @param {Number} level Type of heading (h<level> tag)
* @returns {String} Sidebar element