1- import  React ,  { 
2-     CSSProperties , 
3-     ReactNode , 
4-     useCallback , 
5-     useLayoutEffect , 
6-     useRef , 
7-     useState , 
8- }  from  'react' ; 
1+ import  React ,  {  ReactNode ,  useCallback  }  from  'react' ; 
92import  {  Tooltip  }  from  'antd' ; 
103import  {  AbstractTooltipProps ,  RenderFunction  }  from  'antd/lib/tooltip' ; 
114import  classNames  from  'classnames' ; 
125
136import  Resize  from  '../resize' ; 
7+ import  useTextStyle  from  './useTextStyle' ; 
148import  './style.scss' ; 
159
1610export  interface  IEllipsisTextProps  extends  AbstractTooltipProps  { 
1711    /** 
1812     * 文本内容 
1913     */ 
20-     value : string   |   number   |   ReactNode  |  RenderFunction ; 
14+     value : ReactNode  |  RenderFunction ; 
2115    /** 
2216     * 提示内容 
2317     * @default  value 
@@ -41,12 +35,6 @@ export interface IEllipsisTextProps extends AbstractTooltipProps {
4135    [ propName : string ] : any ; 
4236} 
4337
44- export  interface  NewHTMLElement  extends  HTMLElement  { 
45-     currentStyle ?: CSSStyleDeclaration ; 
46- } 
47- 
48- const  DEFAULT_MAX_WIDTH  =  120 ; 
49- 
5038const  EllipsisText  =  ( props : IEllipsisTextProps )  =>  { 
5139    const  { 
5240        value, 
@@ -56,190 +44,22 @@ const EllipsisText = (props: IEllipsisTextProps) => {
5644        watchParentSizeChange =  false , 
5745        ...otherProps 
5846    }  =  props ; 
47+     const  [ ref ,  isOverflow ,  style ,  onResize ]  =  useTextStyle ( value ,  maxWidth ) ; 
5948
60-     const  ellipsisRef  =  useRef < HTMLSpanElement > ( null ) ; 
6149    const  observerEle  = 
62-         watchParentSizeChange  &&  ellipsisRef . current ?. parentElement 
63-             ? ellipsisRef . current ?. parentElement 
64-             : null ; 
65- 
66-     const  [ visible ,  setVisible ]  =  useState ( false ) ; 
67-     const  [ width ,  setWidth ]  =  useState < number  |  string > ( DEFAULT_MAX_WIDTH ) ; 
68-     const  [ cursor ,  setCursor ]  =  useState ( 'default' ) ; 
69- 
70-     useLayoutEffect ( ( )  =>  { 
71-         onResize ( ) ; 
72-     } ,  [ value ,  maxWidth ] ) ; 
73- 
74-     /** 
75-      * @description : 根据属性名,获取dom的属性值 
76-      * @param  {NewHTMLElement } dom 
77-      * @param  {string } attr 
78-      * @return  {* } 
79-      */ 
80-     const  getStyle  =  ( dom : NewHTMLElement ,  attr : string )  =>  { 
81-         // Compatible width IE8 
82-         // @ts -ignore 
83-         return  window . getComputedStyle ( dom ) [ attr ]  ||  dom . currentStyle [ attr ] ; 
84-     } ; 
85- 
86-     /** 
87-      * @description : 根据属性名,获取dom的属性值为number的属性。如: height、width。。。 
88-      * @param  {NewHTMLElement } dom 
89-      * @param  {string } attr 
90-      * @return  {* } 
91-      */ 
92-     const  getNumTypeStyleValue  =  ( dom : NewHTMLElement ,  attr : string )  =>  { 
93-         return  parseInt ( getStyle ( dom ,  attr ) ) ; 
94-     } ; 
95- 
96-     /** 
97-      * @description : 10 -> 10, 
98-      * @description : 10px -> 10, 
99-      * @description : 90% -> ele.width * 0.9 
100-      * @description : calc(100% - 32px) -> ele.width - 32 
101-      * @param  {* } ele 
102-      * @param  {string & number } maxWidth 
103-      * @return  {* } 
104-      */ 
105-     const  transitionWidth  =  ( ele : HTMLElement ,  maxWidth : string  |  number )  =>  { 
106-         const  eleWidth  =  getActualWidth ( ele ) ; 
107- 
108-         if  ( typeof  maxWidth  ===  'number' )  { 
109-             return  maxWidth  >  eleWidth  ? eleWidth  : maxWidth ;  // 如果父元素的宽度小于传入的最大宽度,返回父元素的宽度 
110-         } 
111- 
112-         const  numMatch  =  maxWidth . match ( / ^ ( \d + ) ( p x ) ? $ / ) ; 
113-         if  ( numMatch )  { 
114-             return  + numMatch [ 1 ]  >  eleWidth  ? eleWidth  : + numMatch [ 1 ] ;  // 如果父元素的宽度小于传入的最大宽度,返回父元素的宽度 
115-         } 
116- 
117-         const  percentMatch  =  maxWidth . match ( / ^ ( \d + ) % $ / ) ; 
118-         if  ( percentMatch )  { 
119-             return  eleWidth  *  ( parseInt ( percentMatch [ 1 ] )  /  100 ) ; 
120-         } 
121- 
122-         const  relativeMatch  =  maxWidth . match ( / ^ c a l c \( 1 0 0 %   -   ( \d + ) p x \) $ / ) ; 
123-         if  ( relativeMatch )  { 
124-             return  eleWidth  -  parseInt ( relativeMatch [ 1 ] ) ; 
125-         } 
126- 
127-         return  eleWidth ; 
128-     } ; 
129- 
130-     const  hideEleContent  =  ( node : HTMLElement )  =>  { 
131-         node . style . display  =  'none' ; 
132-     } ; 
133- 
134-     const  showEleContent  =  ( node : HTMLElement )  =>  { 
135-         node . style . display  =  'inline-block' ; 
136-     } ; 
137- 
138-     /** 
139-      * @description : 获取能够得到宽度的最近父元素宽度。行内元素无法获得宽度,需向上查找父元素 
140-      * @param  {HTMLElement } ele 
141-      * @return  {* } 
142-      */ 
143-     const  getContainerWidth  =  ( ele : HTMLElement ) : number  |  string  =>  { 
144-         if  ( ! ele )  return  DEFAULT_MAX_WIDTH ; 
145- 
146-         const  {  scrollWidth,  parentElement }  =  ele ; 
147- 
148-         // 如果是行内元素,获取不到宽度,则向上寻找父元素 
149-         if  ( scrollWidth  ===  0 )  { 
150-             return  getContainerWidth ( parentElement ! ) ; 
151-         } 
152-         // 如果设置了最大宽度,则直接返回宽度 
153-         if  ( maxWidth )  { 
154-             return  transitionWidth ( ele ,  maxWidth ) ; 
155-         } 
156- 
157-         hideEleContent ( ellipsisRef . current ! ) ; 
158- 
159-         const  availableWidth  =  getAvailableWidth ( ele ) ; 
160- 
161-         return  availableWidth  <  0  ? 0  : availableWidth ; 
162-     } ; 
163- 
164-     /** 
165-      * @description : 获取dom元素的内容宽度 
166-      * @param  {HTMLElement } ele 
167-      * @return  {* } 
168-      */ 
169-     const  getRangeWidth  =  ( ele : HTMLElement ) : any  =>  { 
170-         const  range  =  document . createRange ( ) ; 
171-         range . selectNodeContents ( ele ) ; 
172-         const  rangeWidth  =  range . getBoundingClientRect ( ) . width ; 
173- 
174-         return  rangeWidth ; 
175-     } ; 
176- 
177-     /** 
178-      * @description : 获取元素不包括 padding 的宽度 
179-      * @param  {HTMLElement } ele 
180-      * @return  {* } 
181-      */ 
182-     const  getActualWidth  =  ( ele : HTMLElement )  =>  { 
183-         const  width  =  ele . getBoundingClientRect ( ) . width ; 
184-         const  paddingLeft  =  getNumTypeStyleValue ( ele ,  'paddingLeft' ) ; 
185-         const  paddingRight  =  getNumTypeStyleValue ( ele ,  'paddingRight' ) ; 
186-         return  width  -  paddingLeft  -  paddingRight ; 
187-     } ; 
188- 
189-     /** 
190-      * @description : 获取dom的可用宽度 
191-      * @param  {HTMLElement } ele 
192-      * @return  {* } 
193-      */ 
194-     const  getAvailableWidth  =  ( ele : HTMLElement )  =>  { 
195-         const  width  =  getActualWidth ( ele ) ; 
196-         const  contentWidth  =  getRangeWidth ( ele ) ; 
197-         const  ellipsisWidth  =  width  -  contentWidth ; 
198-         return  ellipsisWidth ; 
199-     } ; 
200- 
201-     /** 
202-      * @description : 计算父元素的宽度是否满足内容的大小 
203-      * @return  {* } 
204-      */ 
205-     const  onResize  =  ( )  =>  { 
206-         const  ellipsisNode  =  ellipsisRef . current ! ; 
207-         const  parentElement  =  ellipsisNode . parentElement ! ; 
208-         const  rangeWidth  =  getRangeWidth ( ellipsisNode ) ; 
209-         const  containerWidth  =  getContainerWidth ( parentElement ) ; 
210-         const  visible  =  rangeWidth  >  containerWidth ; 
211-         setVisible ( visible ) ; 
212-         setWidth ( containerWidth ) ; 
213-         const  parentCursor  =  getStyle ( parentElement ,  'cursor' ) ; 
214-         if  ( parentCursor  !==  'default' )  { 
215-             // 继承父元素的 hover 手势 
216-             setCursor ( parentCursor ) ; 
217-         }  else  { 
218-             // 截取文本时,则改变 hover 手势为 pointer 
219-             visible  &&  setCursor ( 'pointer' ) ; 
220-         } 
221-         showEleContent ( ellipsisNode ) ; 
222-     } ; 
50+         watchParentSizeChange  &&  ref . current ?. parentElement  ? ref . current ?. parentElement  : null ; 
22351
22452    const  renderText  =  useCallback ( ( )  =>  { 
225-         const  style : CSSProperties  =  { 
226-             maxWidth : width , 
227-             cursor, 
228-         } ; 
22953        return  ( 
230-             < span 
231-                 ref = { ellipsisRef } 
232-                 className = { classNames ( 'dtc-ellipsis-text' ,  className ) } 
233-                 style = { style } 
234-             > 
54+             < span  ref = { ref }  className = { classNames ( 'dtc-ellipsis-text' ,  className ) }  style = { style } > 
23555                { typeof  value  ===  'function'  ? value ( )  : value } 
23656            </ span > 
23757        ) ; 
238-     } ,  [ width ,   cursor ,  value ] ) ; 
58+     } ,  [ style ,  value ] ) ; 
23959
24060    return  ( 
24161        < Resize  onResize = { onResize }  observerEle = { observerEle } > 
242-             { visible  ? ( 
62+             { isOverflow  ? ( 
24363                < Tooltip  title = { title }  mouseEnterDelay = { 0 }  mouseLeaveDelay = { 0 }  { ...otherProps } > 
24464                    { renderText ( ) } 
24565                </ Tooltip > 
0 commit comments