React Hook的利用示例(3)

import React from 'react' import { useContext } from 'react' import classNames from 'classnames' import { MenuContext } from './menu' export interface MenuItemProps { index: string; disabled?: boolean; className?: string; style?: React.CSSProperties; } const MenuItem: React.FC<MenuItemProps> = (props) => { const { index, disabled, className, style, children } = props const context = useContext(MenuContext) const classes = classNames('menu-item', className, { 'is-disabled': disabled, // 实现高亮的详细逻辑 'is-active': context.index === index }) const handleClick = () => { // disabled之后就不能利用onSelect,index因为是可选的,所以大概不存在,需要用typeof来做一个判定 if (context.onSelect && !disabled && (typeof index === 'string')) { context.onSelect(index) } } return ( <li className={classes} style={style} onClick={handleClick}> {children} </li> ) } MenuItem.displayName = 'MenuItem' export default MenuItem

最后是SubMenu子组件:

import React, { useContext, FunctionComponentElement, useState } from 'react' import classNames from 'classnames' import { MenuContext } from './menu' import { MenuItemProps } from './menuItem' export interface SubMenuProps { index?: string; title: string; className?: string } const SubMenu: React.FC<SubMenuProps> = ({ index, title, children, className }) => { const context = useContext(MenuContext) // 接下来会利用string数组的一些要领,所以先举办范例断言,将其断言为string数组范例 const openedSubMenus = context.defaultOpenSubMenus as Array<string> // 利用include判定有没有index const isOpened = (index && context.mode === 'vertical') ? openedSubMenus.includes(index) : false const [ menuOpen, setOpen ] = useState(isOpened) // isOpened返回的会是true可能false,这样就是一个动态值 const classes = classNames('menu-item submenu-item', className, { 'is-active': context.index === index }) // 用于实现显示或埋没下拉菜单 const handleClick = (e: React.MouseEvent) => { e.preventDefault() setOpen(!menuOpen) } let timer: any // toggle用于判定是打开照旧封锁 const handleMouse = (e: React.MouseEvent, toggle: boolean) => { clearTimeout(timer) e.preventDefault() timer = setTimeout(()=> { setOpen(toggle) }, 300) } // 三元表达式,纵向 const clickEvents = context.mode === 'vertical' ? { onClick: handleClick } : {} const hoverEvents = context.mode === 'horizontal' ? { onMouseEnter: (e: React.MouseEvent) => { handleMouse(e, true) }, onMouseLeave: (e: React.MouseEvent) => { handleMouse(e, false) }, } : {} // 用于渲染下拉菜单中的内容 // 返回两个值,第一个是child,第二个是index,用i暗示 const renderChildren = () => { const subMenuClasses = classNames('menu-submenu', { 'menu-opened': menuOpen }) // 下面成果用于实此刻subMenu里只能有MenuItem const childrenComponent = React.Children.map(children, (child, i) => { const childElement = child as FunctionComponentElement<MenuItemProps> if (childElement.type.displayName === 'MenuItem') { return React.cloneElement(childElement, { index: `${index}-${i}` }) } else { console.error("Warning: SubMenu has a child which is not a MenuItem component") } }) return ( <ul className={subMenuClasses}> {childrenComponent} </ul> ) } return ( // 展开运算符,向内里添加成果,hover放在外面 <li key={index} className={classes} {...hoverEvents}> <div className="submenu-title" {...clickEvents}> {title} </div> {renderChildren()} </li> ) } SubMenu.displayName = 'SubMenu' export default SubMenu

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsjywp.html