mirror of
https://github.com/saicaca/fuwari.git
synced 2026-01-11 23:02:53 +01:00
fix: revise TOC logic (#252)
fix bugs in fallback, markVisibleSection; refine rAF and connectedCb
This commit is contained in:
@@ -75,30 +75,22 @@ class TableOfContents extends HTMLElement {
|
|||||||
this.observer = new IntersectionObserver(
|
this.observer = new IntersectionObserver(
|
||||||
this.markVisibleSection, { threshold: 0 }
|
this.markVisibleSection, { threshold: 0 }
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
markVisibleSection = (entries: IntersectionObserverEntry[]) => {
|
markVisibleSection = (entries: IntersectionObserverEntry[]) => {
|
||||||
requestAnimationFrame(() => {
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
const id = entry.target.children[0]?.getAttribute("id");
|
const id = entry.target.children[0]?.getAttribute("id");
|
||||||
|
|
||||||
const idx = id ? this.headingIdxMap.get(id) : undefined;
|
const idx = id ? this.headingIdxMap.get(id) : undefined;
|
||||||
|
|
||||||
if (entry.isIntersecting && this.anchorNavTarget == entry.target)
|
|
||||||
this.anchorNavTarget = null;
|
|
||||||
|
|
||||||
if (idx != undefined)
|
if (idx != undefined)
|
||||||
this.active[idx] = entry.isIntersecting;
|
this.active[idx] = entry.isIntersecting;
|
||||||
|
|
||||||
|
if (entry.isIntersecting && this.anchorNavTarget == entry.target.firstChild)
|
||||||
|
this.anchorNavTarget = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
if (!this.active.includes(true))
|
||||||
if (!document.querySelector(`#toc .${this.visibleClass}`)) {
|
|
||||||
this.fallback();
|
this.fallback();
|
||||||
}
|
this.update();
|
||||||
this.toggleActiveHeading();
|
|
||||||
this.scrollToActiveHeading();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleActiveHeading = () => {
|
toggleActiveHeading = () => {
|
||||||
@@ -132,7 +124,7 @@ class TableOfContents extends HTMLElement {
|
|||||||
|
|
||||||
if (this.anchorNavTarget || !this.tocEl) return;
|
if (this.anchorNavTarget || !this.tocEl) return;
|
||||||
const activeHeading =
|
const activeHeading =
|
||||||
document.querySelectorAll<HTMLDivElement>("#toc .visible");
|
document.querySelectorAll<HTMLDivElement>(`#toc .${this.visibleClass}`);
|
||||||
if (!activeHeading.length) return;
|
if (!activeHeading.length) return;
|
||||||
|
|
||||||
const topmost = activeHeading[0];
|
const topmost = activeHeading[0];
|
||||||
@@ -153,6 +145,15 @@ class TableOfContents extends HTMLElement {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
update = () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.toggleActiveHeading();
|
||||||
|
// requestAnimationFrame(() => {
|
||||||
|
this.scrollToActiveHeading();
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
fallback = () => {
|
fallback = () => {
|
||||||
if (!this.sections.length) return;
|
if (!this.sections.length) return;
|
||||||
|
|
||||||
@@ -165,17 +166,13 @@ class TableOfContents extends HTMLElement {
|
|||||||
|| (offsetTop < 0 && offsetBottom > window.innerHeight)) {
|
|| (offsetTop < 0 && offsetBottom > window.innerHeight)) {
|
||||||
this.markActiveHeading(i);
|
this.markActiveHeading(i);
|
||||||
}
|
}
|
||||||
else break;
|
else if (offsetTop > window.innerHeight) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
this.toggleActiveHeading();
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
markActiveHeading = (idx: number)=> {
|
markActiveHeading = (idx: number)=> {
|
||||||
this.active[idx] = true;
|
this.active[idx] = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
handleAnchorClick = (event: Event) => {
|
handleAnchorClick = (event: Event) => {
|
||||||
const anchor = event
|
const anchor = event
|
||||||
@@ -195,14 +192,19 @@ class TableOfContents extends HTMLElement {
|
|||||||
|
|
||||||
isInRange(value: number, min: number, max: number) {
|
isInRange(value: number, min: number, max: number) {
|
||||||
return min < value && value < max;
|
return min < value && value < max;
|
||||||
}
|
};
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
// wait for the onload animation to finish, which makes the `getBoundingClientRect` return correct values
|
// wait for the onload animation to finish, which makes the `getBoundingClientRect` return correct values
|
||||||
setTimeout(() => {
|
const element = document.querySelector('.prose');
|
||||||
|
if (element) {
|
||||||
|
element.addEventListener('animationend', () => {
|
||||||
this.init();
|
this.init();
|
||||||
}, 250);
|
}, { once: true });
|
||||||
|
} else {
|
||||||
|
console.warn('Animation element not found');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.tocEl = document.getElementById(
|
this.tocEl = document.getElementById(
|
||||||
@@ -221,6 +223,8 @@ class TableOfContents extends HTMLElement {
|
|||||||
document.querySelectorAll<HTMLAnchorElement>("#toc a[href^='#']")
|
document.querySelectorAll<HTMLAnchorElement>("#toc a[href^='#']")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (this.tocEntries.length === 0) return;
|
||||||
|
|
||||||
this.sections = new Array(this.tocEntries.length);
|
this.sections = new Array(this.tocEntries.length);
|
||||||
this.headings = new Array(this.tocEntries.length);
|
this.headings = new Array(this.tocEntries.length);
|
||||||
for (let i = 0; i < this.tocEntries.length; i++) {
|
for (let i = 0; i < this.tocEntries.length; i++) {
|
||||||
@@ -240,8 +244,8 @@ class TableOfContents extends HTMLElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.fallback();
|
this.fallback();
|
||||||
this.scrollToActiveHeading();
|
this.update();
|
||||||
}
|
};
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.sections.forEach((section) =>
|
this.sections.forEach((section) =>
|
||||||
@@ -249,7 +253,7 @@ class TableOfContents extends HTMLElement {
|
|||||||
);
|
);
|
||||||
this.observer.disconnect();
|
this.observer.disconnect();
|
||||||
this.tocEl?.removeEventListener("click", this.handleAnchorClick);
|
this.tocEl?.removeEventListener("click", this.handleAnchorClick);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("table-of-contents", TableOfContents);
|
customElements.define("table-of-contents", TableOfContents);
|
||||||
|
|||||||
Reference in New Issue
Block a user