.ellipsis-container
text-align left
position relative
line-height 1.5
padding 0 !important
.textarea-container
position absolute
left 0
right 0
pointer-events none
opacity 0
z-index -1
textarea
vertical-align middle
padding 0
resize none
overflow hidden
font-size inherit
line-height inherit
outline none
border none
2、如何计算字符串截取长度x——双边逼近法(二分思想) 5 Q5 p- b! `+ v% |- p; O3 S* p4 u 只要可以判断一段文字是否超过指定行数,那我们就可以动态地尝试截取字符串,直到找到合适的截断长度x。这个长度满足从x的位置截断字符串,前半部分+“...查看全部”等文字刚好不会超出指定行数N,但是多截取一个字,则会超出N行。 * z4 u% L; G2 v7 D( `3 y 最直观的想法就是直接遍历,让x从0开始增长到显示文本总长度,对于每个x值,都计算一次文字是否超过N行,没超过则加继续遍历,超过则获得了合适的长度x - 1,跳出循环。当然也可以让x从文本总长度递减遍历。" X: O. Q$ r+ ~. O+ ]$ W
不过这里最大的问题在于浏览器的回流和重绘。因为我们每次截取字符串都需要浏览器重新渲染出来才能得到是否超过N行,这过程中就触发了浏览器的重绘或回流,每次循环都会触发一次。" R0 p" [( `* U J
而对于正常的需求来说,假设N取值是3,那很可能每次计算会导致50次以上的重绘或回流,这中间消耗的性能还是非常大的,不小心可能就是几十毫秒甚至上百毫秒。2 N9 F0 z% ^, u* ~- P
这个计算过程应该在一个任务(即常说的”宏任务“)中完成,否则计算过程中会出现显示闪动的”异常“情况,所以可以说计算过程是阻塞的,因此计算的总时间一定要控制到非常低,即要减少计算的次数。 3 v" p' [* q6 V 可以考虑使用"双边逼近法"(或称”二分法“)查找合适的截取长度x,大大减少尝试的次数。第一次先以文本长度为截取长度,计算是否超过N行,没超过则停止计算;超过则取1/2长度进行截取,如果此时没超过N行,则在1/2长度到文本长度之间继续二分查找,如果超过则在0到1/2文本长度中继续二分查找。 7 {' \) G. {" k: ], N 直到查找区间开始值与结束值相差为1,则开始值即为所求。具体实现可以看下文中的完整代码。' ~# m v0 K+ J' x+ w 3、监听页面变动 7 L8 z9 M5 O' R) g( d 对于vue项目来说,传入组件的字符串、行数等可能随时改变,可以watch这些属性变化,然后重新计算一次截取长度。) \: u, `* R9 N& F. T& l
另一方面,对于页面布局而言,可能会因为其它页面元素的增删或者样式改变,导致页面布局变动,影响到文本容器的宽度,此时也应该重新计算一次截取长度。 r; X& E3 R i5 N1 F1 y w" @, I
监听文本容器宽度的变化,可以考虑使用ResizeObserver来监听,但是这个接口的兼容性不够好(IE各个版本都不支持),因此选择了一个npm库element-resize-detector来监测(非常好用)。; |9 o' }8 [; v1 i6 t& c+ a, c7 r 三、代码实现 ; h7 c' q. p6 ` 完整的代码实现如下: % b ]; W4 T% L$ r Y: t& E9 h - |0 L. ^( m) ]& W* n1 q7 ^2 H, P1 N