packages/rc-components/rc-truncate/src/Truncate.tsx (148 lines of code) (raw):

import React from 'react' import { SizeMe } from 'react-sizeme' import classnames from 'classnames' import TruncateByLength from './TruncateByLength' import TruncateByWidth from './TruncateByWidth' import { wrapperClassName } from './constants' import { SWrapper } from './styles' import type { ITruncateProps } from './types/ITruncateProps.type' export type { ITruncateProps } // 一般来说,都可以通过react-sizeme的refreshMode:"debounce"来提高首屏渲染性能, // 避免react-sizeme对DOM的度量阻塞渲染。 // 保险起见,我们通过一个配置来开启这个行为,不要影响已有用户 const debouncedMesure = (() => { if ( typeof window !== undefined && // @ts-ignore window['console-components-truncate-mesure'] === 'debounce' ) { return true } return false })() /** * @public */ const Truncate: React.FC<ITruncateProps> = ({ children, type = 'length', value, threshold, tooltip, showTooltip, align = 'r', omission = '...', tooltipMaxWidth, className, style, updaterRef, isOverflowChange, popupStyle, popupClassName, patchPopupProps, }) => { const actuallShowTooltip = (() => { // 旧版组件支持tooltip prop,且'enable'表示true if (showTooltip !== undefined) return showTooltip if (tooltip !== undefined) { return tooltip === true || tooltip === 'enable' } return true })() const actualThreshold: number | string = (() => { if (threshold !== undefined) { return threshold } if (value !== undefined) { // 旧版API: value可以为30、'30'、'30px' if (typeof value === 'number') { // value可以是40 return value } const parsed = parseInt(value, 10) if (!Number.isNaN(parsed)) { // value可以是'40' return parsed } if (type === 'width' && typeof value === 'string') { // 仅当type为'width'时,value可以是'40px'这种【非纯数字字符串】 return value } console.error( `type can't be string unless type is 'width', using default: 30` ) } return 30 })() if ( type === 'length' && // type 视为 'length' 的前提: typeof children === 'string' && actualThreshold !== 'auto' ) { return ( <Wrapper className={className} style={style}> <TruncateByLength threshold={actualThreshold as number} omission={omission} showTooltip={actuallShowTooltip} align={align} tooltipMaxWidth={tooltipMaxWidth} popupStyle={popupStyle} popupClassName={popupClassName} patchPopupProps={patchPopupProps} > {children} </TruncateByLength> </Wrapper> ) } // 其余情况 type 视为 'width' if (actualThreshold === 'auto') { return ( <SizeMe noPlaceholder refreshMode={debouncedMesure ? 'debounce' : undefined} > {({ size }) => { // 获得可用宽度(即Wrapper的宽度) let actualActualThreshold: number // 设置一个超大的Threshold,使得react-sizeme能拿到完整内容的宽度 if (!size.width) actualActualThreshold = 5000 else actualActualThreshold = size.width return ( <Wrapper className={className} style={style}> <TruncateByWidth threshold={actualActualThreshold} omission={omission} showTooltip={actuallShowTooltip} align={align} tooltipMaxWidth={tooltipMaxWidth} updaterRef={updaterRef} isOverflowChange={isOverflowChange} popupStyle={popupStyle} popupClassName={popupClassName} patchPopupProps={patchPopupProps} > {children} </TruncateByWidth> </Wrapper> ) }} </SizeMe> ) } return ( <Wrapper className={className} style={style}> <TruncateByWidth threshold={actualThreshold as number} omission={omission} showTooltip={actuallShowTooltip} align={align} tooltipMaxWidth={tooltipMaxWidth} updaterRef={updaterRef} isOverflowChange={isOverflowChange} popupStyle={popupStyle} popupClassName={popupClassName} patchPopupProps={patchPopupProps} > {children} </TruncateByWidth> </Wrapper> ) } export default Truncate const Wrapper: React.FC<{ className?: string style?: React.CSSProperties }> = ({ className, children, style }) => { return ( <SWrapper className={classnames(wrapperClassName, className)} style={style}> {children} </SWrapper> ) }