AuchorMenu组件
可适用场景布局分为两个部分,内容区域和锚点区域,内容区域可上下滚动,同时影响锚点目标区域高亮,锚点区域可点击,影响内容区域滚动到指定区域
组件代码
import React, { useEffect } from 'react';
import { Affix } from 'antd';
import styles from './index.less';
export function Anchormenu(props: {
menu: { label: string; value: string }[];
targetId: string;
}) {
const handelScroll = () => {
// 不通设备或浏览器版本scrollTop 可能会出现浮点数,而元素的offsetTop肯定是整数,浮点数的一点差距可能会影响下面的判断,因此做兼容处理向上取整
const targetArea = document.querySelector(props.targetId);
const scrollTop = Math.ceil(targetArea?.scrollTop as number);
const li_list = document.querySelectorAll(`ul.${styles.anchor} > li`);
for (let i = 0; i < props.menu.length; i++) {
const eleOffsetTop = document.getElementById(
props.menu[i].value,
)!.offsetTop;
let nextEleOffsetTop = 0;
if (i < props.menu.length - 1) {
nextEleOffsetTop = document.getElementById(
props.menu[i + 1].value,
)!.offsetTop;
if (i === 0) {
if (scrollTop < nextEleOffsetTop) {
li_list.forEach((el) => el.classList.remove(`${styles.active}`));
li_list[i].classList.add(`${styles.active}`);
}
} else {
if (eleOffsetTop <= scrollTop && scrollTop < nextEleOffsetTop) {
li_list.forEach((el) => el.classList.remove(`${styles.active}`));
li_list[i].classList.add(`${styles.active}`);
}
}
} else {
if (eleOffsetTop <= scrollTop) {
li_list.forEach((el) => el.classList.remove(`${styles.active}`));
li_list[i].classList.add(`${styles.active}`);
}
}
}
};
useEffect(() => {
const targetArea = document.querySelector(props.targetId);
targetArea?.addEventListener('scroll', handelScroll);
return () => {
targetArea?.removeEventListener('scroll', handelScroll);
};
}, []);
const targetScroll = (target: string) => {
const targetEle = document.getElementById(target);
const targetArea = document.querySelector(props.targetId);
targetArea?.scrollTo({ top: targetEle!.offsetTop, behavior: 'smooth' });
};
return (
<Affix>
<ul
style={{
width: 14,
position: 'absolute',
right: 20,
top: 8,
textAlign: 'center',
}}
>
{props?.menu?.map((item, index) => {
if (index === 0) {
return (
<li
onClick={() => targetScroll(item.value)}
className={styles.active}
key={item.value}
>
<a>{item.label}</a>
</li>
);
}
return (
<li
key={item.value}
onClick={() => {
targetScroll(item.value);
}}
>
<a>{item.label}</a>
</li>
);
})}
</ul>
</Affix>
);
}
样式代码
.anchor {
margin: 0;
padding: 0;
list-style: none;
li {
height: 17px;
line-height: 17px;
font-size: 12px;
}
a {
color: rgb(0 0 0 / 65%);
}
}
.anchor .active {
a {
color: #3751ff;
}
}