需求:SideBar 侧边导航与内容区域交互
- 点击侧边栏某一项时,相对应内容区域滚动到视口顶部
- 滚动视口区域,到某一项内容区域,侧边栏选中状态也会跟着变化
typescript
const SideBarAgain: React.FC<PopupProps> = (props) => {
// 父组件传过来的值
const { tabList } = props
const mainElementRef = useRef<HTMLDivElement>(null)
// 用来监听页面滚动事件
const scroll = useScroll(mainElementRef);
const mainElement = mainElementRef.current
const state = useReactive({ activeKey: '1' });
const handleScroll = (key?:string) => {
// 滚动时,需要修改侧边栏选中状态
// 过滤出元素顶部到视窗的距离大于0的元素
const currentKey = tabList.filter((item: { key: string })=>{
const element = document.getElementById(`anchor-${item.key}`)
if (!element) return
const rect = element.getBoundingClientRect()
if (rect.top >= 0) {
return item
}
})
// 判断如果currentKey大于0,则选取第一个key值
if(currentKey.length){
state.activeKey = currentKey[0].key
}else{
state.activeKey = tabList[tabList.length-1].key
}
// 点击侧边栏传入的ID,并滚动到对应位置
if(key){
document.getElementById(`anchor-${key}`)?.scrollIntoView({behavior: "smooth"})
state.activeKey = key
}
}
useEffect(() => {
if (!mainElement) return
mainElement.addEventListener('scroll', () => handleScroll)
return () => {
mainElement.removeEventListener('scroll', () => handleScroll)
}
}, [])
// 利用scroll的变化监听handleScroll
useLayoutEffect(() => handleScroll,[scroll])
return (
<div className='sider'>
<SideBar activeKey={state.activeKey} onChange={(key)=>handleScroll(key)}>
{tabList.map((item: { key: string, title: string }) => (
<SideBar.Item key={item.key} title={item.title} />
))}
</SideBar>
<div className='main' ref={mainElementRef}>
{tabList.map((item: { key: string; title: string; text: string}) => (
<div key={item.key} id={`anchor-${item.key}`} >
<h2>{item.title}</h2>
{item.text}
</div>
))}
</div>
</div>
)
}
export default SideBarAgain;