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

如何计算?

  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. gdb 初次运行卡住 Starting program: [New Thread 0x1103 of process 843]

    安装完后gdb一般会有提示: ==> gdbgdb requires special privileges to access Mach ports.You will need to codes ...

  2. Qt编写可视化大屏电子看板系统29-模块7品质管理

    一.前言 品质管理模块是在送检合格模块的基础上增加了统计而来,总共包括了三个子模块:品质占比.班组合格率.每日合格率统计,其中品质占比子模块采用饼图控件显示对应的百分比,不同百分比颜色不一样,这个饼图 ...

  3. Qt编写的项目作品21-网络请求客户端/服务器

    一.实现原理 http请求就是tcp通信,所以第一步实例化QTcpServer类监听端口,并绑定newConnection信号槽. 一旦有新的连接,交给专门的解包类处理,将对应的数据解包,http请求 ...

  4. 记一次简单的存储过程和Pivot行转列

    首先我很讨厌写存储过程,其次我很讨厌 没办法,主要是需要进行 行转列,项目经理说可以用Pivot.我不是很精通sql,但是我会百度呀~ pivot需要有确定的列名.那我这个项目里面没办法确定,最后问了 ...

  5. .NET Bioss相关数据读写

    本文我们介绍针对Bios如何读取.写入数据,比如最常见的SN读取以及烧录 WMI查询 先看看WMI方式,可以用于查询和管理Windows系统的各种信息,包括读取BIOS信息 WMI-Win32_BIO ...

  6. DVWA靶场JavaScript Attacks漏洞low(低),medium(中等),high(高),impossible(不可能的)所有级别通关教程

    JavaScript Attacks (前端攻击) JavaScript Attacks(前端攻击)漏洞通常涉及利用Web应用程序中的安全漏洞,特别是在JavaScript代码的使用和实现上,从而对用 ...

  7. runoob-设计模式

    https://www.runoob.com/design-pattern/design-pattern-tutorial.html 设计模式(Design pattern)代表了最佳的实践,通常被有 ...

  8. biancheng-NumPy教程

    目录http://c.biancheng.net/numpy/ 1NumPy是什么2NumPy下载与安装3NumPy ndarray对象4NumPy数据类型5NumPy数组属性6Numpy创建数组7N ...

  9. LESLIE NOTE ——你的笔记只属于你自己

    LESLIE NOTE 网站:http://www.leslienote.com 简介: [只有数据可控,才是最放心的] [只有多多备份,才是最安全的] LESLIE NOTE 是一款本地笔记软件, ...

  10. 数组中的常见异常: 1. 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion 2. 空指针异常:NullPointerException

    数组中的常见异常:  1. 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion   2. 空指针异常:NullPointerException package com.ch ...