hexo-theme-keep/source/js/toc.js

108 lines
3.5 KiB
JavaScript
Raw Normal View History

2020-04-21 10:47:36 +08:00
window.addEventListener('DOMContentLoaded', () => {
const articleToc = document.querySelector('.article-toc');
const postTocWrap = document.querySelector('.post-toc-wrap');
const navItems = postTocWrap.querySelectorAll('.post-toc li');
const headerWrapper = document.querySelector('.header-wrapper');
2020-04-21 10:47:36 +08:00
if (navItems.length > 0) {
2020-04-21 10:47:36 +08:00
const sections = [...navItems].map(element => {
let link = element.querySelector('a.nav-link');
// TOC item animation navigate.
link.addEventListener('click', event => {
event.preventDefault();
let target = document.getElementById(event.currentTarget.getAttribute('href').replace('#', ''));
let offset = target.getBoundingClientRect().top + window.scrollY - 18;
window.anime({
targets: document.scrollingElement,
duration: 500,
easing: 'linear',
scrollTop: offset,
complete: function () {
setTimeout(() => {
if (headerWrapper.style.opacity !== '0') headerWrapper.style.opacity = '0'
}, 100)
}
2020-04-21 10:47:36 +08:00
});
});
return document.getElementById(link.getAttribute('href').replace('#', ''));
});
2020-04-21 10:47:36 +08:00
function activateNavByIndex(target) {
if (target.classList.contains('active-current')) return;
document.querySelectorAll('.post-toc .active').forEach(element => {
element.classList.remove('active', 'active-current');
});
target.classList.add('active', 'active-current');
let parent = target.parentNode;
while (!parent.matches('.post-toc')) {
if (parent.matches('li')) parent.classList.add('active');
parent = parent.parentNode;
}
// Scrolling to center active TOC element if TOC content is taller then viewport.
window.anime({
targets: postTocWrap,
duration: 200,
easing: 'linear',
scrollTop: postTocWrap.scrollTop - (postTocWrap.offsetHeight / 2) + target.getBoundingClientRect().top - postTocWrap.getBoundingClientRect().top
});
}
2020-04-21 10:47:36 +08:00
function findIndex(entries) {
let index = 0;
let entry = entries[index];
if (entry.boundingClientRect.top > 0) {
index = sections.indexOf(entry.target);
return index === 0 ? 0 : index - 1;
}
for (; index < entries.length; index++) {
if (entries[index].boundingClientRect.top <= 0) {
entry = entries[index];
} else {
return sections.indexOf(entry.target);
2020-04-21 10:47:36 +08:00
}
}
return sections.indexOf(entry.target);
}
2020-04-21 10:47:36 +08:00
function createIntersectionObserver(marginTop) {
2020-04-21 10:47:36 +08:00
marginTop = Math.floor(marginTop + 10000);
let intersectionObserver = new IntersectionObserver((entries, observe) => {
let scrollHeight = document.documentElement.scrollHeight + 100;
if (scrollHeight > marginTop) {
observe.disconnect();
createIntersectionObserver(scrollHeight);
return;
2020-04-21 10:47:36 +08:00
}
let index = findIndex(entries);
activateNavByIndex(navItems[index]);
}, {
rootMargin: marginTop + 'px 0px -100% 0px',
threshold: 0
});
sections.forEach(element => {
element && intersectionObserver.observe(element);
});
}
2020-04-21 10:47:36 +08:00
createIntersectionObserver(document.documentElement.scrollHeight);
2020-04-21 10:47:36 +08:00
} else {
2020-09-02 19:17:24 +08:00
if (postTocWrap) {
postTocWrap.innerHTML = '';
postTocWrap.style.display = 'none';
}
2020-09-02 19:17:24 +08:00
if (articleToc) {
articleToc.style.display = 'none';
2020-04-21 10:47:36 +08:00
}
}
2020-04-21 10:47:36 +08:00
});