最新版jQuery v3.3.1的BUG以及解决办法(什么问题不重要,怎么解决问题才重要)
发现问题
最新版的 FineUIPro v5.2.0 中,我们将内置的 jQuery v1.12.4 升级到 jQuery v3.3.1 ,可以看升级记录:
+升级到jQuery v3.3.1。
-jQuery v3.x支持的浏览器:Chrome,Edge,Firefox,Safari,IE9+。
-增加类型JSLibrary枚举值JQv1,用来引入jQuery v1.x。
-如果需要支持IE8,请在Web.config中增加配置项JSLibrary=JQv1。
-IE8有限支持并且复杂页面可能会有性能问题,建议大家积极引导用户使用现代浏览器。
之所以做这个升级,主要考虑如下因素:
1. IE8的市场份额逐渐萎缩,可以考虑将IE8的支持放到次要位置
2. 通过全部配置参数 JSLibrary=JQv1 引入老版本的 jQuery v1.12.4,这样老客户仍然可以支持IE8
3. 默认使用 jQuery v3.3.1,紧跟jQuery版本意味着较好的性能和安全性,以及遇到问题能够及时解决
4. 考虑到 jQuery 这么多年的发展,稳定性应该不是问题
整个升级过程还是很平缓的,没有大的改动。
唯一让我头疼的时,好像表格中节点的位置总计算不对,比如在表格的单元格编辑时,如果表格没有滚动条,显示的编辑框是正确的:
但是,表格的滚动条一出现,编辑框就错位了:
而这个问题,在使用 jQuery v1.12.4 时是不存在的!
分析问题
经过一段时间的调试,最终确定这是最新版 jQuery v3.3.1 的一个BUG,出现这个问题需满足如下条件:
1. 引用最新版 jQuery v3.3.1
2. 计算表格 tr 或者 td 的相对位置时出错,比如:$('table tr:eq(1) td(0)').position()
为了更直观的演示这个问题,我写了个例子,其中HTML代码块:
<div class="container">
<table>
<tr>
<td>row-1</td>
</tr>
<tr>
<td id="theTD">row-2</td>
</tr>
</table>
</div>
<div id="result">
</div>
CSS代码块:
.container {
background-color: lightgreen;
padding: 50px;
position: relative;
} table {
width: 100%;
border-collapse: collapse;
border-spacing:;
background-color: green;
} table td {
padding:;
height: 50px;
color: #fff;
vertical-align: top;
}
为了更直观的描述问题,我们用不同的背景色标识外层的容器(.container)和内部的表格(table)。
JavaScript代码块:
$(function() {
var tdPosition = $('#theTD').position();
$('#result').html('top:' + tdPosition.top + ' left:' + tdPosition.left);
});
按照正常的思维模式,上面的 theTD 的相对位置应该是相对 .container 的偏移量(因为 .container 是 td 的第一个遇到的相对定位的父元素)。
因为 .container 设置了 50px 的内边距,表格每行的高度为 50px,所以 theTD 距离 .container 的垂直高度应该是 100px。
所以我们期望的输出结果应该是:
top:100 left:50
但是结果真的如此吗?我创建了两个示例,分别是引用 jQuery v1.9.1 的示例 和 引用 jQuery v3.3.1 的示例,得到的结果如下所示:
可见,在 jQuery v3.3.1 中,获取表格中 td 节点的相对位置(position)得到的结果并不是我们想要的。那这个值到底是什么?
top: 50 left:0
解决问题
经过认真分析,我认为这个值是 td 相对外部 table 节点的偏移量,而不是相对于第一个浮动父节点的位置(position: relative / absolute)。
曾经一度我对 position() 和 offset() 的确切含义产生了怀疑,难道是我理解错了?后来发现我的理解没有问题:
.offsetParent() is supposed to return the nearest positioned element, where "positioned" means it has a css position attribute of "relative", "absolute", or "fixed".
我在很多地方依赖于 position 的计算解决,难道是 jQuery 计算 offsetParent 节点时出了差错:
打开浏览器的调试窗口,我输入如下代码:
$('#theTD').offsetParent()
可见,通过 jQuery 获取到的依然是 .container, 这个方法返回的没问题。
没办法,既然出了问题,只好先在自己的代码中修正了。
第一次尝试
既然 td 的相对位置是相对于 table,那不如用 table 做个中转,计算出 table 的 position 加上去不就行了,如下所示:
$(function() {
var tdPosition = $('#theTD').position();
var tablePosition = $('#theTD').parents('table').position(); $('#result').html('top:' +
(tdPosition.top + tablePosition.top) + ' left:' +
(tdPosition.left + tablePosition.left)); });
看着好像是正确的,后来测试发现遇到嵌套表格就不行了,如下示例:
<div class="container">
<table class="table-outer">
<tr>
<td>table1-row1</td>
</tr>
<tr>
<td>
<table>
<tr>
<td>row-1</td>
</tr>
<tr>
<td id="theTD">row-2</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<div id="result">
</div>
.container {
background-color: lightgreen;
padding: 50px;
position: relative;
} .table-outer {
background-color: blue;
}
table {
width: 100%;
border-collapse: collapse;
border-spacing:;
background-color: green;
} table td {
padding:;
height: 50px;
color: #fff;
vertical-align: top;
}
第二次尝试
一计不成,再生一计。既然 table 的 position 出问题,那么 div 的 position 应该是正常的吧。这次我就来在 td 里面动态创建一个 div 节点怎么样?
$(function() {
var tmpDiv = $('<div style="position:relative;"/>').prependTo($('#theTD'));
var tdPosition = tmpDiv.position();
tmpDiv.remove(); $('#result').html('top:' + tdPosition.top + ' left:' + tdPosition.left);
});
看着好像没有问题,可以问题依旧,当设置 td 的 vertical-align: middle 时,问题暴露出来了,因为此时 td 内的 div 是居中显示的:
第三次尝试
就在我一筹莫展时,我忽然想到前面的 offsetParent() 函数,这个函数能获取正确的父节点。既然 position() 函数有问题,我何不尝试 offset() 函数。
1. jQuery.position(): 获取元素相对于父元素的偏移量(position: relative / absolute)
2. jQuery.offset(): 获取元素相对于视口的偏移量
$(function() {
var tdOffset = $('#theTD').offset();
var tdParentOffset = $('#theTD').offsetParent().offset();
$('#result').html('top:' + (tdOffset.top - tdParentOffset.top) + ' left:' + (tdOffset.left - tdParentOffset.left));
});
这次使用当前元素和相对父元素的 offset 相减,得到的结果是否我们所需要的呢?
不错,正是我们所需要的。因为这个逻辑判断很简单,和是否表格嵌套没关系,所以测试下第一次尝试失败的情况:
Bingo! 一切正常。此问题圆满解决!
真是的jQuery的BUG吗?
想想就不可思议,一个被全球用户使用的公共JavaScript居然有这样的BUG,难道就没人发现么?
网上搜索了一圈,看起来我多虑了,早就有用户提出这个问题:
https://github.com/jquery/api.jquery.com/issues/1081
Per the spec, an offsetParent is defined as an element with a position that is non-static or is a table, th, or td element. Since 3.3.0,
position
started using the nativeoffsetParent
property which started respected table, th, and td as offset parents, but the.offsetParent()
method was left unchanged. We'll fix this in an upcoming release, but we'll need to note the special behavior for those 3 elements in the docs.
这个是 jQuery 核心开发团队给出的答案,大意是说 offsetParent 这个节点属性指的是这样一个父节点:
1. 节点是非静态的,也就是拥有 position: relative / absolute / fixed 样式
2. 节点是 table, th 或者 td
哈,这么多年过去了,我居然第一次听说 offsetParent 还有相对于 td,th,table这个说法,尽管这个td,th,table节点是 position:static,下面使用代码来验证一下:
$(function() {
var tdPosition = $('#theTD').position();
var offsetParent = $('#theTD').offsetParent()[0].tagName;
var nativeOffsetParent = $('#theTD')[0].offsetParent.tagName;
$('#result').html('top:' + tdPosition.top + ' left:' + tdPosition.left +
'<br>offsetParent():' + offsetParent +
'<br>Native offsetParent:' + nativeOffsetParent);
});
分别在不同浏览器中查看结果。
Chrome:
Firefox:
Edge:
IE11(由于IE11打不开jsfiddle网站,我们单独创建了一个页面):
甚至IE9也是这样的:
好吧,看来我真是孤陋而寡闻了。
jQuery 是在 v3.3.0 开始考虑到第二种情况的,但是 jQuery.offsetParent() 的定义没有改变。这种不一致性本身就是一个BUG。
而不和之前的 jQuery v1.x, v2.x 乃至于 v3.3.0 之前的版本兼容,对于一个广泛使用的公共库而言,更应该算是一个BUG,或者至少提供兼容之间的方法。
考虑另一个更现实的问题:在实际应用中,我们为什么要获取 td ,table 的 position() 呢?
不是为了拿获取到的值去更新其他 td 或者 table 的 top/left 属性!
而是为了拿获取的值去更新其他相关 div 节点的 top/left 属性,而 div 节点的 position() 是相对于 position: relative / absolute / fixed 父节点的,而非 td ,table 节点,这就一定会出问题。
所以,我们还是认定这是一个BUG。
但是 jQuery 官方貌似没有修正这个问题的意思,而是可能在将来版本修改 jQuery.offsetParent() 的定义:
但是jQuery你这样做真的好么,都10多年了你都没遵守标准,突然来个小版本号称支持标准,搞的和之前的代码不兼容,你让之前的代码情何以堪!
不管怎样,我们有了自己的解决办法。
小结
这篇文章描述了我们 FineUIPro 产品 更新中遇到的一个问题,最终将问题定位到 jQuery.position() 函数,虽然jQuery的做法是依照HTML规范来的,但是 jQuery.offsetParent() 和 jQuery.position() 两个函数有冲突,并且会导致之前的jQuery插件出错,应该算是一个BUG吧。
好在本文给出了一个补救的方法,如果这里的方法能够对你有所启发或者帮助,就给个推荐呗。
最新版jQuery v3.3.1的BUG以及解决办法(什么问题不重要,怎么解决问题才重要)的更多相关文章
- 【转载】IE浏览器常见的9个css Bug以及解决办法
IE浏览器常见的9个css Bug以及解决办法 我们在浏览网页的时候经常看见这样的现象:某个网页在IE6浏览器中打开很正常,但是在IE8里面打开可能完全变形了.或者也有可能出现完全相反的现象.这让We ...
- MyEclipse的JQuery.min.js报错红叉解决办法
MyEclipse的JQuery.min.js报错红叉解决办法 1.选中报错的jquery文件"jquery-1.2.6.min.js".2.右键选择 MyEclipse--> ...
- Dumpzilla工具第615行bug的解决办法
Dumpzilla工具第615行bug的解决办法 在Dumpzilla使用选项frequency时,会提示SQL语法错误.这是由于其中SQL语句编写错误.需要将615行中: where url l ...
- 记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法
原文:记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法 转载请注明出处:http://www.cnblogs.com/Ray1024 一.问题描述 在MFC中使用Dir ...
- jQuery事件委托之Safari失效的解决办法--摘抄
什么是事件委托 事件委托是Jquery中一种事件绑定的方式,不同于常见的事件绑定方式将事件绑定在目标元素上,而是将事件绑定在父级元素上通过事件冒泡来执行绑定函数. //常见的事件绑定(Jquery) ...
- RCP: P2 Update两个烦人bug和解决办法
问题 Eclipse新的P2 Update机制,使用起来很方便,如果使用P2 plugin自带的UI,开发者完全不用写任何代码 即可实现application的在线更新. 但是P2 Update至少有 ...
- (原创)spring mvc和jersey rest 组合使用时单例对像实例化两次的BUG及解决办法
项目中没用spring 的restTemplate 而是采用 jersey来做rest 的实现,一直用着,也没发现有什么不对,后来加入了,以quartz用硬编码方式实现,结果启动项目的时候报错 ,具体 ...
- ie6双边距bug及其解决办法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【转】JS浮点数运算Bug的解决办法
37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数) 我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 怎么会这样,两个只有一 ...
随机推荐
- Elasticsearch倒排索引结构
一切设计都是为了提高搜索的性能 倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引.通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key. 先来回 ...
- 广告等第三方应用嵌入到web页面方案 之 使用iframe嵌入
有些项目中可能会遇到这样的需求, 需要在一个项目中嵌入其他的项目的页面或者功能.并且需要这两个页面之间能够进行交互. 本文主要介绍如何实现这种第三方应用的嵌入, 主要有以下几个方向: 1.iframe ...
- SnackbarUtilDemo【Snackbar的封装类】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个工具类参考的是<没时间解释了,快使用Snackbar!——Android Snackbar花式使用指南>,代码几乎一 ...
- GetTypes Unable to load one or more of the requested types
重新生成项目,更新反射类的dll文件
- SpringBoot实用小技巧之动态设置SpringBoot日志级别
有时线上问题我们用打日志的方式来观察错误或埋点参数,但由于这些日志如果都打出来会占用大量存储空间而且覆盖了一些有效信息,所以线上级别一般设置INFO,调试级别用作特殊情况下.此时如果线上想查看调试级别 ...
- JVM平台上的响应式流(Reactive Streams)规范
// Reactive Streams // 响应式流是一个倡议,用来为具有非阻塞后压的异步流处理提供一个标准.大家努力的目标集中在运行时环境(JVM和JavaScript)和网络协议上. 注:响应式 ...
- JDBC事务控制
概念 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并 ...
- 能够玩转BKY皮肤的 geek,有一半最后都成为了前端大师
By Conmajia March 9, 2018 剩下的那一半全部扑街了. 世纪之初,BKY那些花里胡哨的预设皮肤曾经让初识网络的懵懂学子雀跃不已. 然而以现在的审美眼光看来,这些带着一股子扑面而来 ...
- 💈 线程间互访助手类 (EN)
Conmajia © 2012, 2018 Published on August 5th, 2012 Updated on February 2nd, 2019 Introduction While ...
- oracle学习笔记(六) JDBC使用
JDBC使用 1. 导包 直接使用IDEA导入依赖包即可 新建一个lib,把jar包放在这里 2. 加载驱动 Class.forName("oracle.jdbc.driver.Oracle ...