diff --git a/packages/renderless/src/anchor/index.ts b/packages/renderless/src/anchor/index.ts index 8e268069d3..624212927f 100644 --- a/packages/renderless/src/anchor/index.ts +++ b/packages/renderless/src/anchor/index.ts @@ -168,11 +168,11 @@ export const onItersectionObserver = ({ state, props, api, vm, emit }: Pick) => () => { const { expandLink, scrollContainer } = state + const { topOffset } = props state.currentLink && updateSkidPosition({ vm, state, emit }) + const rootMargin = topOffset ? `${-topOffset}px 0px 0px 0px` : '' state.intersectionObserver = new IntersectionObserver( (entries) => { - const { top } = scrollContainer.getBoundingClientRect() - const scrollStartTop = top + state.offsetTop entries.forEach((item) => { const key = item.target.id state.observerLinks[key] = item @@ -194,11 +194,7 @@ export const onItersectionObserver = for (let key in state.observerLinks) { if (Object.prototype.hasOwnProperty.call(state.observerLinks, key)) { const item = state.observerLinks[key] - if ( - item.isIntersecting && - item.intersectionRatio >= 0 && - item.target.getBoundingClientRect().top < scrollStartTop - ) { + if (item.isIntersecting && item.intersectionRatio >= 0) { const link = `#${item.target.id}` if (!expandLink[link].children) { api.getCurrentAnchor(link) @@ -210,7 +206,7 @@ export const onItersectionObserver = } } }, - { root: scrollContainer, threshold: [0, 0.25, 0.5, 1] } + { root: scrollContainer, threshold: [0, 0.25, 0.5, 1], rootMargin } ) addObserver({ props, state }) @@ -232,7 +228,11 @@ export const linkClick = if (scrollContainer && scrollContainer !== document.body && !isChangeHash) { const linkEl = scrollContainer.querySelector(item.link) as HTMLElement - const top = linkEl?.offsetTop - scrollContainer.offsetTop // 修复横向锚点无法滚动到顶部 + const top = + linkEl?.getBoundingClientRect().top - + scrollContainer.getBoundingClientRect().top + + scrollContainer.scrollTop - + props.topOffset // 修复横向锚点无法滚动到顶部 const param = { top, left: 0, behavior: 'smooth' } as ScrollToOptions scrollContainer?.scrollTo(param) scrollContainer?.addEventListener('scroll', api.handleScroll()) diff --git a/packages/vue/src/anchor/src/index.ts b/packages/vue/src/anchor/src/index.ts index 682b703d30..4b0b1de1fe 100644 --- a/packages/vue/src/anchor/src/index.ts +++ b/packages/vue/src/anchor/src/index.ts @@ -32,6 +32,10 @@ export const anchorProps = { type: { type: String, default: 'line' + }, + topOffset: { + type: Number, + default: 0 } } diff --git a/packages/vue/src/anchor/src/pc.vue b/packages/vue/src/anchor/src/pc.vue index 655864759c..17b31989f3 100644 --- a/packages/vue/src/anchor/src/pc.vue +++ b/packages/vue/src/anchor/src/pc.vue @@ -7,7 +7,7 @@ import type { IAnchorApi } from '@opentiny/vue-renderless/types/anchor.type' export default defineComponent({ name: $prefix + 'Anchor', directives: { AutoTip }, - props: [...props, 'isAffix', 'links', 'containerId', 'markClass', 'type'], + props: [...props, 'isAffix', 'links', 'containerId', 'markClass', 'type', 'topOffset'], emits: ['linkClick', 'onChange', 'change'], // deprecated v3.12.0废弃,v3.17.0移除onChange 事件 setup(props, context) { return setup({ props, context, renderless, api }) as unknown as IAnchorApi