自定义Menu组件
第一步:定义props
MenuProps
接口定义了 Menu
组件接收的 props,包括默认高亮项、样式、模式、选择项的回调函数和子组件。
export interface MenuProps{
defaultIndex?: number; //高亮
className?: string;
mode: MenuMode; //纵向横向
style?: React.CSSProperties;
onSelect?: (selectedIndex:number)=>void; //选择第几项
children:React.ReactNode;
}
第二步:简单的menu组件实现
const Menu : React.FC<MenuProps> = (props) => {
const {
className,
mode='horizontal',
style,
children,
defaultIndex=0,
onSelect,
}=props;
const classes = classNames('menu',className,{
'menu-vertical':mode==='vertical'
})
return (
<ul className={classes} style={style}>
{children}
</ul>
)
}
第三步:使用useState控制激活项,添加handleClick
函数用于处理菜单项的点击事件,更新当前激活项并调用 onSelect
回调
const [currentActive,setActive]=useState(defaultIndex);
const handleClick = (index:number) => {
//1.调用onselect 2.active变化
setActive(index);
if(onSelect){
onSelect(index);
}
}
第四步:创建文件menuItem.tsx
完整代码如下
import React ,{useContext} from "react";
import classNames from "classnames";
import { MenuContext } from "./menu.tsx";
export interface MenuItemProps {
index: number;
disabled?: boolean;
className?: string;
style?: React.CSSProperties;
children:React.ReactNode;
}
const MenuItem: React.FC<MenuItemProps>=(props)=>{
const{index,disabled,className,style,children,}=props;
const context = useContext(MenuContext) //上下文部分
const classes=classNames('menu-item',classNames,{
'is-disabled':disabled,
'is-active':context.index===index //上下文部分
})
const handleClick = () => {
if(context.onSelect && !disabled){
context.onSelect(index)
}
}
return(
<li className={classes} style={style} onClick={handleClick}>
{children}
</li>
)
}
export default MenuItem
第五步:创建上下文
interface IMenuContext {
index: number; // 当前选中的索引
onSelect?: (selectedIndex: number) => void; // 选择项的回调
}
export const MenuContext = createContext<IMenuContext>({ index: 0 });
menu组件添加:
const passedContext : IMenuContext = {
index: currentActive ? currentActive : 0,
onSelect: handleClick
}
return (
<ul className={classes} style={style}>
<MenuContext.Provider value={passedContext}>
{children}
</MenuContext.Provider>
</ul>
)
passedContext
对象的作用是将 Menu
组件的状态和行为集中在一个地方,以便通过上下文 (MenuContext.Provider
) 传递给其子组件。子组件可以通过 useContext(MenuContext)
来访问 index
和 onSelect
,从而实现状态的共享和菜单的交互。
完整版menu.tsx代码如下:
import React,{useState,createContext} from "react";
import classNames from "classnames";
type MenuMode = 'horizontal' | 'vertical'
type SelectCallback = (selectedIndex:number)=>void;
export interface MenuProps{
defaultIndex?: number; //高亮
className?: string;
mode: MenuMode; //纵向横向
style?: React.CSSProperties;
onSelect?: (selectedIndex:number)=>void; //选择第几项
children:React.ReactNode;
}
//createContext 是 React 中用于创建上下文的一个 API。
//上下文提供了一种方式,可以在组件树中传递数据,而不必通过每一层组件手动传递 props。
//这样非常适合于共享全局数据,比如用户身份、主题设置或者其他需要在多个组件中共享的状态。
interface IMenuContext{
index: number;
onSelect?: (selectedIndex:number)=>void;
}
export const MenuContext = createContext<IMenuContext>({index:0})
const Menu : React.FC<MenuProps> = (props) => {
const {
className,
mode='horizontal',
style,
children,
defaultIndex=0,
onSelect,
}=props;
const [currentActive,setActive]=useState(defaultIndex);
const classes = classNames('menu',className,{
'menu-vertical':mode==='vertical'
})
const handleClick = (index:number) => {
//1.调用onselect 2.active变化
setActive(index);
if(onSelect){
onSelect(index);
}
}
const passedContext : IMenuContext = {
index: currentActive ? currentActive : 0,
onSelect: handleClick
}
return (
<ul className={classes} style={style}>
<MenuContext.Provider value={passedContext}>
{children}
</MenuContext.Provider>
</ul>
)
}
export default Menu
标签:index,style,const,自定义,Menu,number,React,onSelect,组件
From: https://blog.csdn.net/czy0316/article/details/144756868