前言:前端B端开发,web常常会用到导航栏,下面进行封装
一、组件封装
- 组件名: Navigation
- 入口文件:index.tsx
- 样式文件:index.module.less
index.tsx
import type { CSSProperties } from 'react';
import { useState } from 'react';
import { useCallback, useEffect } from 'react';
import cs from 'classnames';
import Style from './index.module.less';
export interface NavListType {
title: string;
key?: string | number;
}
interface PropsType {
navList: NavListType[];
refContent: React.LegacyRef<HTMLElement> | any;
style?: CSSProperties;
className?: string;
}
/**
* 详情通用导航栏
* @param props
* @returns
*/
const Navigation = (props: PropsType) => {
const { navList = [], refContent = null, style, className } = props;
const [activeIndex, setActiveIndex] = useState<number>(0);
// 导航点击处理
const handleAnchorSelect = useCallback(
(e: number) => {
if (e !== activeIndex) {
setTimeout(() => {
setActiveIndex(e);
}, 10);
}
const parent = refContent?.current;
const parentY = parent.getBoundingClientRect().y;
const child = parent?.children[e];
if (child) {
const scrollY = child?.getBoundingClientRect().y - parentY;
parent?.scrollBy(0, scrollY);
}
},
[activeIndex, refContent, setActiveIndex]
);
// 滚动监听
const onScroll = useCallback(() => {
const { clientHeight, children, scrollTop, scrollHeight } = refContent?.current || {};
if (children && !!children?.length && clientHeight) {
for (let i = 0; i < children?.length; i++) {
const scrollY = children[i]?.getBoundingClientRect()?.y;
const thisHeight = children[i]?.clientHeight;
// 3. 其他的,只要出现在屏幕里面就显示
if (
scrollY < clientHeight &&
scrollY + thisHeight > 0 &&
scrollY + thisHeight <= clientHeight
)
setActiveIndex(i);
}
// 1. 如果滚动到顶部,设置第一个
if (scrollTop === 0) {
setActiveIndex(0);
}
// 2. 如果滚动到底部,设置最后一个
const lastFloatHeight = 30; // 浮动值,距离底部30,不用到底就选中最后一个
if (scrollHeight - lastFloatHeight <= scrollTop + clientHeight) {
setActiveIndex(children?.length - 1);
}
}
}, [refContent, setActiveIndex]);
// 滚动监听挂载
useEffect(() => {
window.addEventListener('scroll', onScroll, true);
}, [onScroll]);
return (
<div className={cs(Style.navigationComp, className)} style={style}>
<div>
{navList.map((item, index) => {
const { title, key } = item;
return (
<div
key={key || `${+index}`}
className={cs(
Style.navigationItem,
index === activeIndex && Style.navigationItem_active
)}
onClick={() => {
handleAnchorSelect(index);
}}
>
{title}
</div>
);
})}
</div>
</div>
);
};
export default Navigation;
index.module.less
.navigationComp {
box-sizing: border-box;
width: 200px;
& > div {
border-left: 1px solid rgba(23, 31, 38, 0.1);
.navigationItem {
margin-bottom: 8px;
height: 26px;
line-height: 26px;
padding-left: 12px;
box-sizing: border-box;
cursor: pointer;
}
.navigationItem_active {
color: #0068FF;
border-left: 2px solid #0068FF;
margin-left: -2px;
cursor: pointer;
}
}
}
二、组件使用
该组件比较简单,使用也比较简单,就不举例了,不懂可以到评论去问哦!