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

如何计算?

  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开源作品28-邮件发送工具

    一.前言 邮件发送工具是好多年前就开源出来的,核心就是调用最底层socket通信来实现的邮件发送程序,以前用C#写过,微软都封装好的,不知道底层是如何实现的,只知道调用方法,这次用C++实现了下,参考 ...

  2. [转]基于vue-router的matched实现面包屑功能

    原文链接:基于vue-router的matched实现面包屑功能

  3. 长连接网关技术专题(十):百度基于Go的千万级统一长连接服务架构实践

    本文由百度技术团队分享,引用自百度Geek说,原题"千万级高性能长连接Go服务架构实践",为了阅读便利,本文进行了排版优化等. 1.引言 移动互联网时代,长连接服务成为了提升应用实 ...

  4. linxux学习01

    Linux第一天 1.为什么要学习linux? 因为大数据中绝大部分核心组件都是基于linux操作系统运行的,企业中基本上都是linux系统. 2.怎么去学linux?(什么是大数据) 大数据技术组件 ...

  5. springboot-多模块构建-2

    三个标签完成springboot定时任务配置 1. 问题描述 Java项目定时任务是必备模块,月高风黑夜跑个批处理,记录或者统计一些系统信息. 2. 解决方案: 结合springboot,只需三个标签 ...

  6. Logstash介绍

    Logstash是一个开源数据收集引擎,具有实时管道功能.Logstash可以动态地将来自不同数据源的数据统一起来,并将数据标准化到你所选择的目的地. 集中.转换和存储你的数据 Logstash是一个 ...

  7. 一个奇葩的SQL题,够强大。

    困惑描述: 现有一张图片表,表里一个sort字段,这个字段是不重复的.不连续的数字.大致结构如下 create table Imgs( `id` bigint(20) NOT NULL AUTO_IN ...

  8. 基础《Go学习笔记》读书笔记——函数

    writer:zgx lastmodify:2020年09月26日 目录 第四章--函数 变参 返回值 匿名函数 闭包 延迟调用 误用 性能 错误处理 error panic, recover Dra ...

  9. Medjed pg walkthrough Intermediate window

    nmap nmap -p- -A -sS -T4 192.168.219.127 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-22 01 ...

  10. 让AI碰撞!“天翼云息壤杯”高校AI大赛江苏赛区交流会热力开场!

    由中国电信集团有限公司主办,天翼云科技有限公司承办的"天翼云息壤杯"高校AI大赛正在火热进行中.为了提高江苏赛区学生的参赛热情,增强学生的创作能力,江苏电信.天翼云华东中心于12月 ...