メニュー
メニューコンポーネントは誰にとっても比較的馴染み深いものです。メニューバーの1つを切り替えて、最初にメニューレンダリングのプライマリバージョンを確認できます。
コンポーネント分析:
4つのスタイルがあり、デフォルトはプライマリ、危険、成功、警告が
あり、次に上下または左右の2つの種類があります。
クリックして切り替えます。
インターフェース
全部で3つあり、最後の1つは、親コンポーネントと子コンポーネント間のデータ共有を実現することです。
1つ目はMenuコンポーネントで、これは基本的にulタグです。渡すことができる値は、現在のハイライトのインデックス、タイプ、スタイル、onSelectコールバック関数、およびクラス名です。
2つ目はMenuItemコンポーネントで、これは基本的にliタグです。渡すことができる値には、Index、disabled、クラス名、スタイルコントロールスタイルが含まれます。
タイプエイリアス
メニューコンポーネントコード
import React, {
useState, createContext } from 'react'
import cx from 'classnames'
import {
IMenuProps, menuType, IMenuContext, IMenuItemProps } from './common'
import {
MenuContext } from './conText'
const Menu: React.FC<IMenuProps> = (props) => {
const {
style, color, className, activeIndex, type, onSelect, children, ...restProps } = props
const classes = cx(
'menu',
className,
{
[`menu-${
type}`]: type,
[`menu-${
style}`]:style,
[`menu-horizontal`]:Boolean(type!=='vertical')
})
const [index, setindex] = useState(activeIndex)
const handle = (index: number) => {
setindex(index)
if (onSelect) {
onSelect(index)
}
}
const value: IMenuContext = {
activeIndex: index!, //感叹号非空,强行告诉编译器,我这个activeInedx不是空的
onSelect: handle
}
//代码升级
const renderChildren = () => {
return React.Children.map(children, (child, index) => {
const chlidElement = child as React.FunctionComponentElement<IMenuItemProps>
if (chlidElement?.type?.displayName !== 'MenuItem') {
//传入的子组件不是MenuItem就报错
console.error('Waring: Menu has a child which is not a MenuItem')
} else {
return React.cloneElement(chlidElement, {
//每次都要传入index,甚是麻烦,cloneElement,可以复制节点并且附加上属性,前提是IMenuItemProps里面有定义的
index
})
}
})
}
return <ul className={
classes} {
...restProps} data-testid="test-menu">
<MenuContext.Provider value={
value}>
{
renderChildren()}
</MenuContext.Provider>
</ul>
}
Menu.defaultProps = {
activeIndex: 0,
type: menuType.Horizontal,
}
export default Menu
スタイルは属性セレクター、スプライシングを使用し、デフォルトはmenu-horizontalで、水平方向にソートされます。
コンテキストを使用してデータを共有し、共有データを
作成します
。2番目の値は関数です。子コンポーネントをクリックすると、インデックスが返され、親コンポーネントがインデックス値を更新してから、外部に渡されたonSelect関数を呼び出します。にインデックス値を渡します。
ここでは関数を使用します
。この関数の主な関数は、渡された子がMenuItemであるかどうかを判別することです。そうでない場合は、エラーを報告します。そうでない場合は、cloneElementを返します。このメソッドは、渡したchildElementをコピーできます。に属性を付加します。index、この方法で作成されたliタグにはindex属性があります。それ以外の場合は、呼び出すときに手動でしか追加できないため、不便です。
現在のハイライトがこのインデックスの値に基づいているかどうかを判断しているため、必要です。
MenuItemコンポーネントコード
import React, {
useContext } from 'react'
import cx from 'classnames'
import {
MenuContext} from './conText'
import {
IMenuItemProps} from './common'
const MenuItem: React.FC<IMenuItemProps> = (props) => {
const {
index, classNames, disabled, style, children, ...restProps } = props
const value = useContext(MenuContext);
const {
activeIndex, onSelect} = value
const classes = cx('menu-item',classNames,{
'menu-item-disabled':disabled,'menu-item-active':Boolean(activeIndex===index)})
const handleClick = () => {
if(onSelect && !disabled &&(typeof index === 'number')){
onSelect(index)
}
}
return (
<li className={
classes} style= {
style} onClick={
handleClick} {
...restProps}>{
children}</li>
)
}
MenuItem.defaultProps = {
disabled:false
}
MenuItem.displayName = 'MenuItem'
export default MenuItem
ここでは簡単です。ハイライトを判断するには、親コンポーネントから渡されたインデックスがそれ自体のインデックス値と同じであるかどうかを判断するだけで済みます。コールバックは、父親から渡されたハンドル、つまりonSelect関数を介してインデックス値を渡すだけで、インデックス値をリアルタイムで変更する効果を実現します。
スタイル
互いに影響を与えずに2つに分割します。
転送