目录悬浮

This commit is contained in:
liuzhihang 2022-10-30 15:14:23 +08:00
parent e6b0407b07
commit 10ac27a069
4 changed files with 159 additions and 105 deletions

View File

@ -77,24 +77,36 @@ document.addEventListener("DOMContentLoaded", function () {
// 滚动处理 // 滚动处理
const scrollFnToDo = function () { const scrollFnToDo = function () {
let $cardTocLayout = document.getElementById("card-toc");
// let $cardToc = $cardTocLayout.getElementsByClassName("toc-content")[0];
// let $tocLink = $cardToc.querySelectorAll(".toc-link");
let $article = document.getElementById("article-container");
// let scrollPercent; const isToc = GLOBAL_CONFIG.htmlType === 'post';
// if (GLOBAL_CONFIG.htmlType === 'post') { const isAnchor = true;
// scrollPercent = function (currentTop) { const $article = document.getElementById("article-container");
// const docHeight = $article.clientHeight;
// const winHeight = document.documentElement.clientHeight; if (!($article && (isToc || isAnchor))) return
// const headerHeight = $article.offsetTop;
// const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand
// const scrollPercent = (currentTop - headerHeight) / (contentMath);
// const scrollPercentRounded = Math.round(100 * scrollPercent); if (isToc) {
// const percentage = 100 < scrollPercentRounded ? 100 : scrollPercentRounded <= 0 ? 0 : scrollPercentRounded;
// $cardToc.setAttribute("progress-percentage", percentage); const $cardTocLayout = document.getElementById("card-toc");
// }; $cardToc = $cardTocLayout.getElementsByClassName("toc-content")[0];
// } $tocLink = $cardToc.querySelectorAll(".toc-link");
// const $tocPercentage = $cardTocLayout.querySelector(".toc-percentage");
isExpand = $cardToc.classList.contains("is-expand");
scrollPercent = function (currentTop) {
const docHeight = $article.clientHeight;
const winHeight = document.documentElement.clientHeight;
const headerHeight = $article.offsetTop;
const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight);
const scrollPercent = (currentTop - headerHeight) / (contentMath);
const scrollPercentRounded = Math.round(scrollPercent * 100);
const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded;
// $tocPercentage.textContent = percentage
$cardToc.setAttribute("progress-percentage", percentage);
};
window.mobileToc = { window.mobileToc = {
open: () => { open: () => {
@ -110,79 +122,90 @@ document.addEventListener("DOMContentLoaded", function () {
} }
// toc 元素点击 // toc 元素点击
// $cardToc.addEventListener("click", e => { $cardToc.addEventListener("click", e => {
// e.preventDefault(); e.preventDefault();
// const target = e.target.classList.contains("toc-link") ? e.target : e.target.parentElement; const target = e.target.classList;
// if (target.contains('toc-content')) return;
// btf.scrollToDest( const $target = e.target.classList.contains("toc-link") ? e.target : e.target.parentElement;
// btf.getEleTop(
// document.getElementById(
// decodeURI(target.getAttribute("href")).replace("#", "")
// )
// ),
// 300
// );
// if (window.innerWidth < 900) {
// window.mobileToc.close();
// }
// });
btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute("href")).replace("#", ""))), 300);
if (window.innerWidth < 900) {
window.mobileToc.close()
}
});
autoScrollToc = item => {
const activePosition = item.getBoundingClientRect().top
const sidebarScrollTop = $cardToc.scrollTop
if (activePosition > (document.documentElement.clientHeight - 100)) {
$cardToc.scrollTop = sidebarScrollTop + 150
}
if (activePosition < 100) {
$cardToc.scrollTop = sidebarScrollTop - 150
}
};
}
// find head position & add active class // find head position & add active class
// const list = $article.querySelectorAll("h1,h2,h3,h4,h5,h6"); const list = $article.querySelectorAll("h1,h2,h3,h4,h5,h6");
// let detectItem = ""; let detectItem = "";
// const findHeadPosition = function (top) { const findHeadPosition = function (top) {
//
// if (0 === $tocLink.length || 0 === top) {
// return false
// }
//
// let currentId = "";
// let currentIndex = "";
//
// list.forEach(function (ele, index) {
// if (top > btf.getEleTop(ele) - 80) {
// currentId = "#" + encodeURI(ele.getAttribute("id"));
// currentIndex = index
// }
//
// })
// if (detectItem === currentIndex) {
// return
// }
//
// detectItem = currentIndex
//
// $cardToc.querySelectorAll(".active").forEach(i => {
// i.classList.remove("active")
// })
//
// if (currentId === "") {
// return
// }
//
// const currentActive = $tocLink[currentIndex]
// currentActive.classList.add("active")
//
// setTimeout(() => {
// autoScrollToc(currentActive)
// }, 0)
//
// if (isExpand) return
// let parent = currentActive.parentNode
//
// for (; !parent.matches(".toc"); parent = parent.parentNode) {
// if (parent.matches("li")) parent.classList.add("active")
// }
// }
// window.tocScrollFn = function () { if (0 === $tocLink.length || 0 === top) {
// return btf.throttle(function () { return false
// let currentTop = window.scrollY || document.documentElement.scrollTop; }
// // scrollPercent(currentTop)
// findHeadPosition(currentTop); let currentId = "";
// }, 100)(); let currentIndex = "";
// };
// window.addEventListener("scroll", tocScrollFn); list.forEach(function (ele, index) {
if (top > btf.getEleTop(ele) - 80) {
const id = ele.id
currentId = id ? "#" + encodeURI(id) : ""
currentIndex = index
}
})
if (detectItem === currentIndex) {
return
}
if (isAnchor) btf.updateAnchor(currentId);
detectItem = currentIndex
if (isToc) {
$cardToc.querySelectorAll(".active").forEach(i => {
i.classList.remove("active")
});
if (currentId === "") {
return;
}
const currentActive = $tocLink[currentIndex];
currentActive.classList.add("active");
setTimeout(() => {
autoScrollToc(currentActive)
}, 0);
if (isExpand) return;
let parent = currentActive.parentNode;
for (; !parent.matches(".toc-list"); parent = parent.parentNode) {
if (parent.matches("li")) parent.classList.add("active")
}
}
}
window.tocScrollFn = function () {
return btf.throttle(function () {
let currentTop = window.scrollY || document.documentElement.scrollTop;
scrollPercent(currentTop)
findHeadPosition(currentTop);
}, 100)();
};
window.addEventListener("scroll", tocScrollFn);
}; };
const tabsFn = { const tabsFn = {

View File

@ -179,6 +179,17 @@ const btf = {
} }
return actualTop return actualTop
},
updateAnchor: (anchor) => {
if (anchor !== window.location.hash) {
if (!anchor) anchor = location.pathname
const title = "123111111111"
window.history.replaceState({
url: location.href,
title: title
}, title, anchor)
}
} }
}; };

View File

@ -1,13 +1,34 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"> <html lang="en" xmlns:th="http://www.thymeleaf.org">
<!-- 侧边栏 -->
<div class="aside-content" id="aside-content" th:fragment="aside(widgets)" <div class="aside-content" id="aside-content" th:fragment="aside(widgets)"
th:if="${theme.config.sidebar.location != 'hide-aside' && not #strings.isEmpty(widgets)}"> th:if="${theme.config.sidebar.location != 'hide-aside' && not #strings.isEmpty(widgets)}">
<!-- 侧栏部件不确定都有什么 --> <!-- 侧栏部件,不包含 toc 则直接遍历 -->
<th:block th:if="${not #strings.contains(widgets, 'toc')}">
<th:block th:each="widget : ${#strings.listSplit(widgets, ',')}"> <th:block th:each="widget : ${#strings.listSplit(widgets, ',')}">
<th:block th:replace="'modules/widgets/aside/'+ ${widget}"/> <th:block th:replace="'modules/widgets/aside/'+ ${widget}"/>
</th:block> </th:block>
</th:block>
<!-- 侧栏部件toc 之后的组件需要被 sticky_layout 包裹 -->
<th:block th:if="${#strings.contains(widgets, 'toc')}">
<th:block th:each="widget : ${#strings.listSplit(#strings.substringBefore(widgets, 'toc'), ',')}">
<th:block th:replace="'modules/widgets/aside/'+ ${widget}"/>
</th:block>
<!-- toc 之后的组件需要被 sticky_layout 包裹 -->
<div class="sticky_layout">
<th:block th:replace="modules/widgets/aside/toc :: toc"/>
<th:block th:each="widget : ${#strings.listSplit(#strings.substringAfter(widgets, 'toc'), ',')}">
<th:block th:replace="'modules/widgets/aside/'+ ${widget}"/>
</th:block>
</div>
</th:block>
</div> </div>

View File

@ -47,10 +47,9 @@
}); });
tocbot.init({ tocbot.init({
tocSelector: '.toc-content', tocSelector: '.toc-content',
contentSelector: '.post-content', contentSelector: content,
headingSelector: headerEl, headingSelector: headerEl,
hasInnerContainers: true, hasInnerContainers: true,
}); });
} }