diff --git a/packages/opendesign/src/_utils/dom.ts b/packages/opendesign/src/_utils/dom.ts index 3fb153fac831f91ae5944cbdbc8d6d4a8ba3f403..21ed193dc8d8c1ebc67a2e17832ff3a726f30476 100644 --- a/packages/opendesign/src/_utils/dom.ts +++ b/packages/opendesign/src/_utils/dom.ts @@ -181,8 +181,55 @@ export function isOverflown(element?: HTMLElement) { if (!element) { return false; } + return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight; +} + +/** + * 判断元素是否在视口内 + */ +export function isInViewport(element?: Element) { + if (!element) { + return false; + } + const rect = element.getBoundingClientRect(); return ( - element.scrollWidth > element.clientWidth || - element.scrollHeight > element.clientHeight + rect.top < (window.innerHeight || document.documentElement.clientHeight) && + rect.bottom > 0 && + rect.left < (window.innerWidth || document.documentElement.clientWidth) && + rect.right > 0 ); } + +/** + * 判断是否为不可见标签 + */ +export function isNonVisibleTag(element: Element) { + const nonVisibleTags = ['SCRIPT', 'STYLE', 'LINK', 'META', 'HEAD']; + return nonVisibleTags.includes(element.tagName); +} + +/** + * 判断元素是否在视觉上隐藏 + */ +export function isElementHidden(element: HTMLElement) { + // 直接检查内联样式 + if (element.style.display === 'none' || element.style.visibility === 'hidden') { + return true; + } + + // 通过getComputedStyle检查计算样式 + const computedStyle = window.getComputedStyle(element); + if ( + computedStyle.display === 'none' || + computedStyle.visibility === 'hidden' || + computedStyle.opacity === '0' || + computedStyle.width === '0px' || + computedStyle.height === '0px' + ) { + return true; + } + + // 检查元素是否在视口外或尺寸为0 + const rect = element.getBoundingClientRect(); + return rect.width === 0 || rect.height === 0; +} diff --git a/packages/opendesign/src/anchor/OAnchor.vue b/packages/opendesign/src/anchor/OAnchor.vue index 6f385ffb427e239a80e16b127d1c7c517f3dcab8..76aa44abc5d8476e86550c1e5ba2dfbfa911f55a 100644 --- a/packages/opendesign/src/anchor/OAnchor.vue +++ b/packages/opendesign/src/anchor/OAnchor.vue @@ -113,12 +113,7 @@ const scrollIntoView = async (link: string) => { isScrolling.value = false; }; -// 滚动事件 -const onScroll = () => { - if (isScrolling.value) { - return; - } - +const activeNearest = () => { const distances: Array<{ link: string; top: number }> = []; const { targetOffset, bounds } = props; @@ -144,6 +139,14 @@ const onScroll = () => { } setActiveLink(active); +} + +// 滚动事件 +const onScroll = () => { + if (isScrolling.value) { + return; + } + activeNearest(); }; const bindEvent = () => { @@ -151,7 +154,7 @@ const bindEvent = () => { return; } - scrollContainer.value.addEventListener('scroll', onScroll); + scrollContainer.value.addEventListener('scroll', onScroll, { passive: true }); }; const unbindEvent = () => { @@ -197,6 +200,8 @@ onMounted(() => { const hash = decodeURIComponent(window.location.hash); if (hash) { scrollIntoView(hash); + } else { + activeNearest(); } nextTick(() => { bindEvent(); diff --git a/packages/opendesign/src/anchor/__demo__/AnchorBasic.vue b/packages/opendesign/src/anchor/__demo__/AnchorBasic.vue index c08f01d9c41194f85c27c492e4ade61140244e3e..0068a74c4fb809bed360c2cc6589f3c7eab4e9d2 100644 --- a/packages/opendesign/src/anchor/__demo__/AnchorBasic.vue +++ b/packages/opendesign/src/anchor/__demo__/AnchorBasic.vue @@ -16,7 +16,7 @@ import { OAnchor, OAnchorItem } from '../index';
medium:
- +