Tags:
TypeScript
IntersectionObserver でビューポート内の一番上にあるパラグラフを取得する
IntersectionObserver でビューポート内の一番上にあるパラグラフを取得する実装をした。
やりたいこととしては、個人サイトで掲載している小説のブックマーク機能を作りたくて、ブックマークしたときにビューポート内の一番上にある文章を取得したい。
/** 探索対象を囲む要素のクラス名 */
const WRAPPER_CLASS = "Wrapper";
/** 交差状態 */
const intersectionStatus: { id: string; isIntersecting: boolean }[] = [];
/** ビューポート内の一番上にあるパラグラフの id を取得 */
function getTopParagraphId(): string {
for (const item of intersectionStatus) {
if (item.isIntersecting) {
const element = document.getElementById(item.id);
if (!element) {
continue;
}
// パラグラフの中身が空でない場合は id を返す
if (element.innerHTML.trim().length > 0) {
return item.id;
}
}
}
// すべてのパラグラフがビューポート外にある場合は一番下のパラグラフを返す
return intersectionStatus[intersectionStatus.length - 1].id;
}
/** 探索対象内のすべての p タグに id を付与し、交差判定する */
function setIdAndIntersectionObserver() {
const wrapperElements = document.getElementsByClassName(WRAPPER_CLASS);
if (wrapperElements.length === 0) {
return;
}
const element = wrapperElements[0];
const paragraphs = element.getElementsByTagName("p");
for (let index = 0; index < paragraphs.length; index++) {
const id = `element-p-${index}`;
paragraphs[index].setAttribute("id", id);
intersectionStatus.push({ id, isIntersecting: false });
}
// 一つの IntersectionObserver インスタンスで複数要素を監視する
const intersectionObserver = new IntersectionObserver((entries) => {
for (const entry of entries) {
const index = intersectionStatus.findIndex(
(item) => item.id === entry.target.id,
);
if (index === -1) {
continue;
}
intersectionStatus[index].isIntersecting = entry.isIntersecting;
}
});
for (const paragraph of paragraphs) {
intersectionObserver.observe(paragraph);
}
}
使い方としては、ページ読み込み後に setIdAndIntersectionObserver
を実行する。
ブックマークのタイミングで getTopParagraphId
を実行して一番上にある要素を取得する。
以上