之前有做过一个业务,需要在文本框输入文字的时候动态计算一行文字的宽度。并由此知道当前输入的这段文字会有几行。

如何计算?

  1. 每个文字的个数*宽度?理论上可行,但是有一个问题是不同类型的文字对应的宽度是不一样的,数字,汉字,字母乃至每个标点符号 宽度各不相同。所以实际处理起来,这个肯定会埋坑。

  2. canvas measureText api ? 理论可行,实际问题 :字体,字间距,。。。引起的其他误差。(其实这些误差也是很容易清除的,所以这些问题也就不叫问题了,我没有采用这种方法完全是因为当时没去往这个方向想)。

不卖关子了,最后我采用的方法是这样的: 首先,我们用一个pre元素(characterElement) 将其所有css属性重置为和我们要计算的文本框的属性相一致。然后把他放置到视口之外,最后结合dom方法计算出其宽度,然后除以文本框的宽度:

  1. function calcRows(texaWidth,charWidth ){
  2. return Math.ceil( charWidth / texaWidth )
  3. }

这是最初的想法,但是这里有个问题是对于换行时的误差处理,因为当当前文字不足以全部放进textarea的时候,是会换行的,而换行前和换行后之间是有空隙的,这个空隙累积之后会对后续结果的计算带来比较大的偏差影响。所以我们还需要计算出换行后上一行多出来的空间所占的元素:

  1. function calcOffset(){
  2. let texaWidth = textArea.getBoundingClientRect().width;
  3. let offset = 0;
  4. for( let i = 1, before = i-1,L = textArea.value.length; i <= L; i++ ){
  5. let str = textArea.value.slice( before, i);
  6. characterElement.innerHTML = str;
  7. let verifyWidth = characterElement.getBoundingClientRect().width;
  8. console.log(verifyWidth,texaWidth)
  9. if( verifyWidth >= texaWidth ){
  10. // 记录换行下标
  11. before = i-1;
  12. offset += ( verifyWidth - texaWidth )
  13. }
  14. }
  15. return offset;
  16. }

有了全部的文字宽度和换行带来的误差累积我们可以很容易就计算出当前这段文字到底占了几行,即:

  1. characterElement.innerHTML = textArea.value;
  2. let verifyWidth = characterElement.getBoundingClientRect().width + calcOffset();
  3. let texaWidth = textArea.getBoundingClientRect().width;
  4. let rows = Math.ceil( verifyWidth / texaWidth )

最后一步需要考虑的是,对于calcOffset函数,每一个文字输入都会产生一个巨量的运算时间,并且随着文字输入的增加,其计算量的增长会非常恐怖,因此, 我们需要一个策略去缓存我们已经计算过的文字:

  1. let cache={
  2. lastIndex:0,
  3. offset:0
  4. };
  5. function calcOffset(){
  6. let texaWidth = textArea.getBoundingClientRect().width;
  7. let before = cache.lastIndex;
  8. for( let i = before + 1,L = textArea.value.length; i <= L; i++ ){
  9. let str = textArea.value.slice( before, i);
  10. characterElement.innerHTML = str;
  11. let verifyWidth = characterElement.getBoundingClientRect().width;
  12. if( verifyWidth >= texaWidth ){
  13. // 记录换行下标
  14. cache.lastIndex = i - 1;
  15. before = i-1;
  16. cache.offset += ( verifyWidth - texaWidth )
  17. }
  18. }
  19. return cache.offset;
  20. }

OK了,这样基本不会有太大问题了,在文本框的input回调里调用这些函数就可以得到精确地行数了,当然可以debounce一下得到性能更优的版本。

后记: 以上代码源于实际项目中的一个评论框,大体样子跟下图差不多,因为涉及到自动换行并且他右边的那一部分是跟文字在同一行的 所以需要去精确地计算文字的宽度

如何用js精确计算一行文字的宽度的更多相关文章

  1. js精确计算

    官方文档:http://mikemcl.github.io/big.js/ 使用方法: x = new Big(0.1); y = x.plus(0.2); // '0.3' var a=Big(0. ...

  2. js精确计算(js浮点数精度问题)

    转自:http://talentluke.iteye.com/blog/1767138 大多数语言在处理浮点数的时候都会遇到精度问题,但是在JS里似乎特别严重,来看一个例子 alert(45.6*13 ...

  3. 实现js浮点数加、减、乘、除的精确计算(网上很多文章里的方法是不能解决所有js浮点数计算误差的)

    最近做项目,要用到js的加.减.乘.除的计算,发现js浮点数计算会有一些误差. 网上有很多文章都有js浮点数计算误差的解决方法,说能解决这个问题,But…….比如一个加法函数,如下: function ...

  4. js浮点数相加、减、乘、除精确计算

    js 浮点数计算时 ,无缘无辜 后边冒出一堆 小数点………… 貌似js本身的问题,类型不定?????? 只能自己写函数处理..  http://blog.csdn.net/w4bobo/article ...

  5. js加减乘除精确计算

    Javascript精确计算时的bug JS无法进行精确计算的bug 在做CRM,二代审核需求审核详情页面时.需要按比例(后端传类似0.8的小数)把用户输入的数字显示在不同的地方. 在做dubheIn ...

  6. js 日期计算星座 根据生日的月份和日期,一行代码计算星座的js小函数(转)

    本博客根据 开源中国作者清风徐不来 的文章 根据生日的月份和日期,一行代码计算星座的js小函数(转) 原文出自CSDN 无心的专栏 的文章,知识产权归原文作者所有! 点击查看原文:js 日期计算星座

  7. JS怎么计算html标签里文字的宽度

    方法: 做一个空的html 标签 id为“ruler”,样式为“position:absolute;visibility: hidden; white-space: nowrap;z-index: - ...

  8. css实现一行文字居中,多行文字左对齐

    问题及场景: 当内容能一行显示在盒子内时,文字居中对齐. 当内容过多换行后显示在盒子内时,文字左对齐. 其实这种视觉上的需求还是蛮常见的.比如用于弹出提示框,当提示内容比较少时,内容居中显示在弹出框, ...

  9. js浮点数计算问题 + 金额大写转换

    一 js浮点数计算问题解决方案: 1.使用 NumberObject.toFixed(num) 方法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 2.较精度计算浮点数 ...

  10. 关于js浮点数计算精度不准确问题的解决办法

    今天在计算商品价格的时候再次遇到js浮点数计算出现误差的问题,以前就一直碰到这个问题,都是简单的使用tofixed方法进行处理一下,这对于一个程序员来说是及其不严谨的.因此在网上收集了一些处理浮点数精 ...

随机推荐

  1. Qt/C++最新地图组件发布/历时半年重构/同时支持各种地图内核/包括百度高德腾讯天地图

    一.前言说明 最近花了半年时间,专门重构了整个地图组件,之前写的比较粗糙,有点为了完成功能而做的,没有考虑太多拓展性和易用性.这套地图自检这几年大量的实际项目和用户使用下来,反馈了不少很好的建议和意见 ...

  2. Qt音视频开发43-采集屏幕桌面并推流(支持分辨率/矩形区域/帧率等设置/实时性极高)

    一.前言 采集电脑屏幕桌面并推流一般是用来做共享桌面.远程协助.投屏之类的应用,最简单入门的做法可能会采用开个定时器或者线程抓图,将整个屏幕截图下来,然后将图片传出去,这种方式很简单但是性能要低不少, ...

  3. Qt编写安防视频监控系统54-轮询配置

    一.前言 视频监控系统中少不了用到视频轮询,按照设计的基本原则,先满足基本的用户需求,稳定跑起来,再去折腾更复杂的应用场景,于是本系统也做了个基本的视频轮询功能,可以设置轮询方案,给某个轮询方案设置轮 ...

  4. Qt音视频开发10-ffmpeg控制播放

    一.前言 很多人在用ffmpeg做视频流解码的时候,都会遇到一个问题,如何暂停,如果打开的是本地视频文件,暂停你只需要停止解码即可,但是视频流你会发现根本没用,一旦你停止了解码,下次重新解码的时候,居 ...

  5. OpenCV4.1.0编译时提示“CV_BGR2GRAY”: 未声明的标识符

    OpenCV版本为4.1.0 使用CV_BGR2GRAY时报错: "CV_BGR2GRAY": 未声明的标识符 解决方法一:添加头文件:#include <opencv2/i ...

  6. [转]Clion中如何使用矩阵库eigen

    CMakelist文件内容如下: cmake_minimum_required(VERSION 3.2) project(PISO) set(CMAKE_CXX_STANDARD 14) includ ...

  7. [转]springboot 监控 Actuator和Admin

    参考链接: 1.springboot 监控 Actuator和Admin 2.SpringBoot:Actuator监控中心+AdminUI界面管理

  8. Solution -「NOI 2017」「洛谷 P3822」整数

    \(\mathscr{Description}\)   Link.   初始有整数 \(x=0\), 给出 \(n\) 次操作, 每次操作为 \(x\gets x+a\cdot2^b\) 或询问 \( ...

  9. kubernetes 使用ceph实现动态持久卷存储

    k8s使用ceph存储 ceph提供底层存储功能,cephfs方式支持k8s的pv的3种访问模式​​ReadWriteOnce,ReadOnlyMany ,ReadWriteMany​​​ ,RBD支 ...

  10. 动态添加html事件无响应

    问题描述:在页面中动态使用js添加的html中设置了onclick事件,生产页面后点击事件无效并提示:Cannot read property 'xxx' of undefined 如: $('.te ...