2.7K Star 16K Fork 3.6K

GVPLayui / layui

 / 详情

分页输入出现负数值

已完成
创建于  
2022-06-16 11:26

全选之后 输入过多的数字就会出现负数值
输入过多的数字
出现负值

评论 (5)

joker 创建了任务

经在此页面反复测试:https://layui.gitee.io/v2/demo/ 未发现负数问题
从截图来看,你并非是在当前官网文档页测试的例子,有可能是后端提供的数据本身没做好分页数控制。

这是在 Gitee 极其少见的能有如此认真和严谨的回复 :+1:
该 BUG 确实存在。| 运算符在早期的目的是为了将任意类型的值化整,但对于位数太长的数字的确处理不妥。
下个版本修复。

因为Layui值得被认真对待 :smile:

尝试复现Bug

经测试官网文档确实有负数情况发生,说一下我的操作:
1、在文档首页右侧表格页跳转输入框中较大的数字值,例如2147483649
step1
2、点击“确定”,输入框内数字变成负值,页码导航栏无对应选中页码。
step2

尝试查找原因

  1. 尝试找出临界值,尝试多个测试用例后发现,不是并不是超过某个值之后就一定会出现这种情况,例如6442450943是大于2147483649,但是这个值正确处理了。
    1.1
    1.2
  2. 尝试从源码中寻找原因。使用谷歌DEBUG跟代码后发现,jump方法中有一行处理输入框值得时候使用了|与0进行位运算,从图中可以看出2147483649与0进行或运算之后变成了一个负数(见Watch中的变量e的值),而这个值就是最后渲染到页面输入框中的值:
    2.1
    2.2

阶段性总结

到这里,应该能够确定,就是这个|运算符出现了问题,有些值在与0进行|时,结果并不等于它本身,而是成为了一个负数值。|0的操作从代码逻辑上来看是将字符串转换成为数字,那么使用Number()进行替换是一种解决方案。
但是问题依然存在,为什么有些很大的值,例如6442450943代码依然能够正常处理,有些例如2147483649不能呢?

继续深挖

  1. 探究|运算符的秘密
    从代码中可以看到,代码是用数字字符串与数字0进行按位或运算,那么自然逻辑(不涉及底层二进制计算逻辑)应该是:

    1. 将字符串转换成数字
    2. 将数字转换成2进制
    3. 进行按位或运算

    W3School的资料中得到了以下信息:

    • JavaScript是基于ECMA-262标准发展的
    • ECMA-262标准中位运算符是在数字底层(即表示数字的 32 个数位)进行操作的
    • 数字底层中,左边第一位为符号位,0为正数,1为负数,其余为数值位

    所以我们可以大概得出,出现负数的可能原因是:js在做位运算时会将数字转换为32位的二进制数,如果不够在前面补0至32为,如果超过则截断取后32位。
    由此我们可以设计一个实验:

    1. 使用10000000000000000000000000000000(二进制长度32位,十进制值:2147483647)与0进行|运算,查看结果。
    2. 使用100000000000000000000000000000000(二进制长度33位,十进制值:4294967296)与0进行|运算,查看结果。
    3. 使用110000000000000000000000000000000(二进制长度33位,十进制值:6442450944)与0进行|运算,查看结果。
    4. 使用0(二进制长度1位,十进制值:0)与0进行|运算,查看结果。

    实验结果:
    实验1结果
    从实验结果中我们可以看到1和3的结果是相同的,2和4的结果是相同的。所以我们可以认为,之前的猜测是正确的。

  2. 探究为何十进制数值6442450943能正常运行
    使用Number中的toString(2)方法查看6442450943的二进制数是101111111111111111111111111111111(二进制长度33),按照上个实验得出的结论应该在位运算中等价与01111111111111111111111111111111(二进制长度32),|0的运算结果是2147483647
    不对劲啊,页面上显示的不是2147483647啊,是在哪里做了处理吗?
    继续追踪代码,最后找到在view方法中有一个逻辑:
    输入图片说明
    可以看到,在这里使n.curr(原本应该是拿来存储当前页码,在此场景下为输入值与0|运算之后的值)与n.pages(服务器返回的最大页数)做了比较,如果n.curr大于n.pages,则将n.pages赋予n.curr,以此来保障当前页数永远小于等于最大页数。
    所以问题出现了,当n.curr是负数的情况下,n.curr小于n.pages时满足的,因此不会执行修正代码,所以最后页面渲染出现了负数。

总结

通过上面的分析及实验我得出了以下结论:

  1. 分页组件中会出现负数的情况是存在的,触发这个bug的条件是,当输入的十进制数值转换为二进制之后,第32位为1的数字。bug产生的原因是在分页组件的jump方法中使用了|来进行数据类型转换,导致js进行了位运算,得出了错误的数值。使用Number()进行替换进行转换是一种可行的方案。
    输入图片说明
  2. 分页组件中的view方法中,考虑到了当前页不能超过最大页的逻辑,但是没有考虑到当前页小于0的情况(正常使用场景下极少出现)
    输入图片说明
贤心 添加了
 
精华
标签

刚刚发布的 v2.7.0 已优化该问题。
同时也特别点赞 @Breakpoint 在本帖中所展现的个人技术素养,虽然只是个小问题,但这种探索的过程和认真对待每一个技术细节的态度,非常令人值得学习。 :thumbsup:

贤心 任务状态待办的 修改为已完成

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(3)
92529 sentsin 1578917144 9109679 zjq0094 1655801003
JavaScript
1
https://gitee.com/layui/layui.git
git@gitee.com:layui/layui.git
layui
layui
layui

搜索帮助

53164aa7 5694891 3bd8fe86 5694891