Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions packages/components/anchor/anchor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,14 @@ export default defineComponent({
if (handleScrollLock.value) return;
const { bounds, targetOffset } = props;
const filters: { top: number; link: string }[] = [];
let active = '';
let nextActive = '';

const isScrollBottom =
scrollContainer.value instanceof HTMLElement &&
Math.abs(
scrollContainer.value.scrollTop + scrollContainer.value.clientHeight - scrollContainer.value.scrollHeight,
) < 2;

// 找出所有当前top小于预设值
links.value.forEach((link) => {
const anchor = getAnchorTarget(link);
Expand All @@ -87,9 +94,33 @@ export default defineComponent({
// 找出小于预设值集合中top最大的
if (filters.length) {
const latest = filters.reduce((prev, cur) => (prev.top > cur.top ? prev : cur));
active = latest.link;
nextActive = latest.link;
}
setCurrentActiveLink(active);

// 如果滚动到底部,且当前计算出的 active 在视口中,且用户没有手动切换到更后的锚点
// 需要判断当前 active 是否由于触底而无法到达顶部触发线
if (isScrollBottom && links.value.length) {
const currentActiveIndex = links.value.indexOf(active.value);
const calcActiveIndex = links.value.indexOf(nextActive);

// 如果当前已经激活的项索引比计算出来的更大,说明它是在底部可见的,不应被跳回到前面的项
if (currentActiveIndex > calcActiveIndex) {
const anchor = getAnchorTarget(active.value);
if (anchor) {
const top = getOffsetTop(anchor, scrollContainer.value);
// 只要还在视口内(元素与视口有重叠),就维持它的激活状态
if (scrollContainer.value instanceof HTMLElement) {
const clientHeight = scrollContainer.value.clientHeight;
const bottom = top + anchor.offsetHeight;
if (bottom > 0 && top < clientHeight) {
nextActive = active.value;
}
}
}
}
}

setCurrentActiveLink(nextActive);
};
/**
* 获取锚点对应的target元素
Expand Down
Loading