观摩一段简单粗暴的 vue 代码

2020-09-29 23:42:59 +08:00
 px920906

是一个 vue 的 updated 生命周期钩子:

  updated () {
    let tx = document.getElementsByClassName('textContent');
    for (let jj = 0; jj < tx.length; jj++) {
      while (tx[jj].offsetHeight < tx[jj].scrollHeight) {
        let ss = tx[jj].innerText;
        tx[jj].innerText = ss.substr(0, ss.length - 4);
        tx[jj].innerText += '...';
      }
    }
  }

页面是一个展示作品的页面,估计是设计要求作品简介的文字所占高度不超过一定值,超出部分裁掉用三个点代替。 作者的做法是等 vue 拿到数据并重新渲染 dom 之后把页面上所有.textContent 元素里的文字逐字删到所占高度刚好不超过元素高度(.textContent 高度固定)。作品有多条,再加上其他数据更新导致的重新渲染,这段代码会执行多次。

可能他 /她在开发和测试过程中没遇到文字很多的情况,现在我们遇到了一个两万字的数据,导致每次刷新页面至少需要 2 分钟,期间页面处于假死状态。用 chrome 性能面板录制了一下,耗时 4 分多钟,上个截图大伙感受一下:

设置 innerText 本身就是会导致强制同步布局的耗时操作,再循环两万次……

不过光指出问题不够,怎么解决?

我自己还真想不出好办法……不过首先会把这段逻辑放在获取作品数据完成后的一个 nextTick 里,而不是 updated 钩子里。另一个是获取到数据后直接限制文字长度为固定值,但不好保证最后行数以及文字末尾在行末,肯定过不了设计的关。或者,两者结合,先限制为一个尽量短但足够的长度,再执行上面的逻辑。

最后查到了-webkit-line-clamp这个 css 属性,感觉不考虑 IE 的话,就是它了。

大家有什么好的方案?

6006 次点击
所在节点    程序员
49 条回复
azh7138m
2020-09-29 23:48:23 +08:00
wangxiang
2020-09-29 23:56:17 +08:00
. textContent {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
NullData
2020-09-30 00:27:47 +08:00
看了之后有一点未经验证的小想法,可能比较粗糙
1.查找算法可以换成二分查找来提升性能
2.每次计算元素高度不用 dom 树中的节点,用 document.createElement 新建一个元素,操作他来避免 dom 树的回流来提升性能。
9yu
2020-09-30 00:37:44 +08:00
css 实现。
noe132
2020-09-30 01:09:15 +08:00
我用类似思路实现过一个动态的多行带省略号的判断。
这个计算只在加载时执行一次,不需要每次 update 都重复计算
加上二分查找,通常不需要太多次就能计算出来
woncode
2020-09-30 02:07:28 +08:00
看不懂用 vue 怎么还要“document.getElementsByClassName”,那不是 jquery 时代的写法,现在的 mvvm 框架不是应该直接在模板去变量绑定,响应式更新吗
Sapp
2020-09-30 02:08:23 +08:00
css 自带这个功能...
Sapp
2020-09-30 02:10:59 +08:00
另外就算不用 css,也不应该这么操作,应该把需要这个操作的文字都封装从一个组件里传入,在这个组件 mounted 之后获取一下高度,然后计算字符数量,从 template 里直接 slice(0,xxx)。计算字符这个操作不需要渲染,直接在内存就能操作
Sapp
2020-09-30 02:14:28 +08:00
最不济的方式也是直接给外层固定高度的元素设置超出的全部隐藏,然后获取一下里面高度,如果高度超出的话给外边添加一个 class,class 的内容是...,通过 position 定位看起来像结尾的 ...。哪有挨个操作 dom 这个骚操作
cxe2v
2020-09-30 02:33:02 +08:00
@Sapp 挨个操作不算骚,这个最骚的是每次循环减掉 4 个字然后看高度达标没,不达标继续循环
Mutoo
2020-09-30 07:11:19 +08:00
可以用二分法优化一下,O(logN),:doge:
KuroNekoFan
2020-09-30 07:53:16 +08:00
这种就是很典型的只懂 vue 的前端开发者能干出来的事了……
akakidz
2020-09-30 08:41:54 +08:00
这是后端写的 Vue 吧 :doge:
f056917
2020-09-30 08:46:50 +08:00
能用 CSS 实现的为什么要用 JS
f056917
2020-09-30 08:47:36 +08:00
单行:

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
多行:

display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
or:

overflow:hidden;
text-overflow:ellipsis;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;


PS:兼容 IE 的话要设置宽度
DOLLOR
2020-09-30 08:47:44 +08:00
这是 jQuery 程序员写的 vue 吧 :doge:
diegozhu
2020-09-30 08:50:46 +08:00
@Sapp 请教一下,mount 后的组件也不能保证算出来的高度就是实际的高度吧?涉及到 style,起码 font-size,line-height,word-spacing 不一样对 size 影响很大。
treblex
2020-09-30 08:56:43 +08:00
有些使用 css,必需要 js 修改的话,在请求接口之后 赋值到 data 之前操作,
treblex
2020-09-30 08:57:01 +08:00
@suke971219 #18 优先 css
hbolive
2020-09-30 08:57:24 +08:00
这明显是 CSS 基础不牢。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/711713

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX