mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-09 09:57:19 +08:00
79 lines
2.8 KiB
JavaScript
79 lines
2.8 KiB
JavaScript
import { onMounted, onUnmounted, onUpdated } from 'vue';
|
|
export function useActiveSidebarLinks() {
|
|
let rootActiveLink = null;
|
|
let activeLink = null;
|
|
const decode = decodeURIComponent;
|
|
const deactiveLink = (link) => link && link.classList.remove('active');
|
|
const activateLink = (hash) => {
|
|
deactiveLink(activeLink);
|
|
deactiveLink(rootActiveLink);
|
|
activeLink = document.querySelector(`.sidebar a[href="${hash}"]`);
|
|
if (activeLink) {
|
|
activeLink.classList.add('active');
|
|
// also add active class to parent h2 anchors
|
|
const rootLi = activeLink.closest('.sidebar > ul > li');
|
|
if (rootLi && rootLi !== activeLink.parentElement) {
|
|
rootActiveLink = rootLi.querySelector('a');
|
|
rootActiveLink && rootActiveLink.classList.add('active');
|
|
}
|
|
else {
|
|
rootActiveLink = null;
|
|
}
|
|
}
|
|
};
|
|
const setActiveLink = () => {
|
|
const sidebarLinks = [].slice.call(document.querySelectorAll('.sidebar a'));
|
|
const anchors = [].slice
|
|
.call(document.querySelectorAll('.header-anchor'))
|
|
.filter((anchor) => sidebarLinks.some((sidebarLink) => sidebarLink.hash === anchor.hash));
|
|
const pageOffset = document.querySelector('.navbar')
|
|
.offsetHeight;
|
|
const scrollTop = window.scrollY;
|
|
const getAnchorTop = (anchor) => anchor.parentElement.offsetTop - pageOffset - 15;
|
|
for (let i = 0; i < anchors.length; i++) {
|
|
const anchor = anchors[i];
|
|
const nextAnchor = anchors[i + 1];
|
|
const isActive = (i === 0 && scrollTop === 0) ||
|
|
(scrollTop >= getAnchorTop(anchor) &&
|
|
(!nextAnchor || scrollTop < getAnchorTop(nextAnchor)));
|
|
// TODO: fix case when at page bottom
|
|
if (isActive) {
|
|
const targetHash = decode(anchor.hash);
|
|
history.replaceState(null, document.title, targetHash);
|
|
activateLink(targetHash);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
const onScroll = throttleAndDebounce(setActiveLink, 300);
|
|
onMounted(() => {
|
|
setActiveLink();
|
|
window.addEventListener('scroll', onScroll);
|
|
});
|
|
onUpdated(() => {
|
|
// sidebar update means a route change
|
|
activateLink(decode(location.hash));
|
|
});
|
|
onUnmounted(() => {
|
|
window.removeEventListener('scroll', onScroll);
|
|
});
|
|
}
|
|
function throttleAndDebounce(fn, delay) {
|
|
let timeout;
|
|
let called = false;
|
|
return () => {
|
|
if (timeout)
|
|
clearTimeout(timeout);
|
|
if (!called) {
|
|
fn();
|
|
called = true;
|
|
setTimeout(() => {
|
|
called = false;
|
|
}, delay);
|
|
}
|
|
else {
|
|
timeout = setTimeout(fn, delay);
|
|
}
|
|
};
|
|
}
|