From 391acfe0d2952bcd4112a1205b76f763208c1b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B5=E7=A5=BA?= Date: Mon, 9 Dec 2024 19:21:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20[breadcrumb]=20=E9=9D=A2=E5=8C=85?= =?UTF-8?q?=E5=B1=91=E7=BB=84=E4=BB=B6=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20fix=20#993?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/breadcrumb/breadcrumb.tsx | 168 +++++++++++------------ components/breadcrumb/breadcrumbItem.tsx | 31 ++++- components/breadcrumb/interface.ts | 3 + 3 files changed, 109 insertions(+), 93 deletions(-) diff --git a/components/breadcrumb/breadcrumb.tsx b/components/breadcrumb/breadcrumb.tsx index 820d8582..1b205f3c 100644 --- a/components/breadcrumb/breadcrumb.tsx +++ b/components/breadcrumb/breadcrumb.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponentElement, useContext, useEffect, useRef } from 'react' +import React, { FunctionComponentElement, useCallback, useContext, useEffect, useRef } from 'react' import classNames from 'classnames' import ConfigContext from '../config-provider/ConfigContext' import { getCompProps } from '../_utils' @@ -24,7 +24,7 @@ const Breadcrumb = (props: IBreadcrumbProps): FunctionComponentElement(null) const [itemsConfig, setItemsConfig] = React.useState(items) const [itemsArray, setItemsArray] = React.useState() - const [breadcrumbWidth, setBreadcrumbWidth] = React.useState() + const [breadcrumbWidth, setBreadcrumbWidth] = React.useState(0) const [openEllipsis, setOpenEllipsis] = React.useState(false) const breadcrumbPrefixCls = getPrefixCls!(prefixCls, 'breadcrumb', customPrefixcls) @@ -33,56 +33,51 @@ const Breadcrumb = (props: IBreadcrumbProps): FunctionComponentElement { - return classNames(item.className, `${breadcrumbPrefixCls}-item`, { - [`${breadcrumbPrefixCls}-item-link`]: item?.path || item?.href, - [`${breadcrumbPrefixCls}-item-${colorModel || 'emphasize'}-model-current`]: isLast, - [`${breadcrumbPrefixCls}-item-${colorModel || 'emphasize'}-model`]: !isLast, - }) - } + const MIN_ITEM = 3 // 加上more只显示3个元素的时候,末尾元素开启省略号 + const isLastItem = (index: number, items: IBreadcrumbItem[]) => { return index === items?.length - 1 } - const getSeparator = (index: number, items: IBreadcrumbItem[]) => { - if (isLastItem(index, items)) { - return null - } else { - return {separator} - } - } - const getMoreIconContent = (items: IBreadcrumbItem[]) => { - const MoreItems = () => { + const getMoreIconContent = useCallback( + (items: IBreadcrumbItem[]) => { + const MoreItems = () => { + return ( +
+ {items.map((item, index) => { + return ( + + ) + })} +
+ ) + } return ( -
- {items.map((item, index) => { - return ( - - ) - })} -
+ <> + } + trigger="hover" + placement="bottomLeft" + > + + + ) - } - return ( - <> - } - trigger="hover" - placement="bottomLeft" - > - - - - ) - } + }, + [breadcrumbMorePanelClass, breadcrumbPopperClass, colorModel, onItemClick, separator], + ) const getElementWidth = (ref: React.RefObject) => { if (ref.current) { @@ -92,37 +87,40 @@ const Breadcrumb = (props: IBreadcrumbProps): FunctionComponentElement { - const difference = getElementWidth(breadcrumbRef) - breadcrumbWidth! - if (difference < 0) { - const number = -difference - const removeItem = widthArr?.reduce( - (acc, cur, ind) => { - if (ind > 0 && ind < widthArr.length - 1) { - if (acc.width < number + getElementWidth(breadcrumbHideIconRef)) { - acc.width += cur.width - acc.index = ind - return acc + const getItemsConfig = useCallback( + (widthArr: IItemsWidth[], breadcrumbWidth: number) => { + const difference = getElementWidth(breadcrumbRef) - breadcrumbWidth! + if (difference < 0) { + const number = -difference + const removeItem = widthArr?.reduce( + (acc, cur, ind) => { + if (ind > 0 && ind < widthArr.length - 1) { + if (acc.width < number + getElementWidth(breadcrumbHideIconRef)) { + acc.width += cur.width + acc.index = ind + return acc + } else { + return acc + } } else { return acc } - } else { - return acc - } - }, - { width: 0, index: 0 }, - ) - if (removeItem.index > 0 && removeItem.index < items.length - 1) { - const newItemsConfig = cloneDeep(items) - newItemsConfig.splice(1, removeItem.index, { - title: getMoreIconContent(cloneDeep(items).splice(1, removeItem.index)), - }) - setItemsConfig(newItemsConfig) + }, + { width: 0, index: 0 }, + ) + if (removeItem.index > 0 && removeItem.index < items.length - 1) { + const newItemsConfig = cloneDeep(items) + newItemsConfig.splice(1, removeItem.index, { + title: getMoreIconContent(cloneDeep(items).splice(1, removeItem.index)), + }) + setItemsConfig(newItemsConfig) + } + } else { + setItemsConfig(items) } - } else { - setItemsConfig(items) - } - } + }, + [getMoreIconContent, items], + ) useEffect(() => { const isMore = itemsConfig?.some((item: any) => { @@ -146,20 +144,17 @@ const Breadcrumb = (props: IBreadcrumbProps): FunctionComponentElement { + const fn = () => { + getItemsConfig(itemsArray, breadcrumbWidth) + } if (itemsArray && breadcrumbWidth) { - window.addEventListener('resize', () => { - getItemsConfig(itemsArray, breadcrumbWidth) - }) + window.addEventListener('resize', fn) } - - return () => - window.removeEventListener('resize', () => { - getItemsConfig(itemsArray, breadcrumbWidth as any) - }) - }, [itemsArray, breadcrumbWidth]) + return () => window.removeEventListener('resize', fn) + }, [itemsArray, breadcrumbWidth, getItemsConfig]) return ( <> @@ -169,13 +164,12 @@ const Breadcrumb = (props: IBreadcrumbProps): FunctionComponentElement ) diff --git a/components/breadcrumb/breadcrumbItem.tsx b/components/breadcrumb/breadcrumbItem.tsx index 7d365333..5bb0f4dd 100644 --- a/components/breadcrumb/breadcrumbItem.tsx +++ b/components/breadcrumb/breadcrumbItem.tsx @@ -1,17 +1,28 @@ -import React, { useContext, FC } from 'react' +import React, { useContext, FC, memo } from 'react' import { IBreadcrumbItems } from './interface' import Dropdown from '../dropdown' import Icon from '../icon' import devWarning from '../_utils/devwarning' import ConfigContext from '../config-provider/ConfigContext' +import classNames from 'classnames' const BreadcrumbItem: FC = (props) => { const { getPrefixCls, prefixCls } = useContext(ConfigContext) - const { item, index, separator, openEllipsis, onItemClick } = props - const { title, className, dropdownProps, href, path, icon } = item + const { item, index, separator, openEllipsis, isLast, isTooltip, colorModel, onItemClick } = props + const { title, dropdownProps, href, path, icon, className } = item const breadcrumbPrefixCls = getPrefixCls!(prefixCls, 'breadcrumb') + const breadcrumbSeparatorClass = classNames(`${breadcrumbPrefixCls}-item-separator`) const itemTextCls = `${breadcrumbPrefixCls}-item-text` const itemIconCls = `${breadcrumbPrefixCls}-item-icon` + + const getBreadcrumbItemClass = () => { + return classNames(className, `${breadcrumbPrefixCls}-item`, { + [`${breadcrumbPrefixCls}-item-link`]: path || href, + [`${breadcrumbPrefixCls}-item-${colorModel || 'emphasize'}-model-current`]: isTooltip ? false : isLast, + [`${breadcrumbPrefixCls}-item-${colorModel || 'emphasize'}-model`]: isTooltip ? true : !isLast, + }) + } + const handleItemClick = () => { if (href && !path) { window.open(href, '_self') @@ -22,9 +33,17 @@ const BreadcrumbItem: FC = (props) => { } onItemClick && onItemClick(item, index) } + + const getSeparator = () => { + if (isLast) { + return null + } else { + return {separator} + } + } return ( <> -
+
{icon &&
{icon}
}
= (props) => { )} - {separator} + {getSeparator()}
) } -export default BreadcrumbItem +export default memo(BreadcrumbItem) diff --git a/components/breadcrumb/interface.ts b/components/breadcrumb/interface.ts index e6d4dffd..b612b278 100644 --- a/components/breadcrumb/interface.ts +++ b/components/breadcrumb/interface.ts @@ -21,6 +21,9 @@ export interface IBreadcrumbItems { index: number separator?: ReactNode openEllipsis?: boolean + colorModel?: ColorModelType // 颜色模式,默认是 'emphasize' + isLast?: boolean + isTooltip?: boolean onItemClick?: (item: IBreadcrumbItem, index: number) => void // 点击面包屑导航的回调函数 }