溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

jQueryv3.3.1的BUG如何解決

發(fā)布時間:2023-03-13 10:11:21 來源:億速云 閱讀:88 作者:iii 欄目:開發(fā)技術

這篇文章主要講解了“jQueryv3.3.1的BUG如何解決”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“jQueryv3.3.1的BUG如何解決”吧!

發(fā)現(xiàn)問題

最新版的 FineUIPro v5.2.0 中,我們將內(nèi)置的 jQuery v1.12.4 升級到 jQuery v3.3.1 ,可以看升級記錄:

+升級到jQuery v3.3.1。
    -jQuery v3.x支持的瀏覽器:Chrome,Edge,F(xiàn)irefox,Safari,IE9+。
    -增加類型JSLibrary枚舉值JQv1,用來引入jQuery v1.x。
    -如果需要支持IE8,請在Web.config中增加配置項JSLibrary=JQv1。
    -IE8有限支持并且復雜頁面可能會有性能問題,建議大家積極引導用戶使用現(xiàn)代瀏覽器。

之所以做這個升級,主要考慮如下因素:

1. IE8的市場份額逐漸萎縮,可以考慮將IE8的支持放到次要位置

2. 通過全部配置參數(shù) JSLibrary=JQv1 引入老版本的 jQuery v1.12.4,這樣老客戶仍然可以支持IE8

3. 默認使用 jQuery v3.3.1,緊跟jQuery版本意味著較好的性能和安全性,以及遇到問題能夠及時解決

4. 考慮到 jQuery 這么多年的發(fā)展,穩(wěn)定性應該不是問題

整個升級過程還是很平緩的,沒有大的改動。

唯一讓我頭疼的時,好像表格中節(jié)點的位置總計算不對,比如在表格的單元格編輯時,如果表格沒有滾動條,顯示的編輯框是正確的:

jQueryv3.3.1的BUG如何解決

但是,表格的滾動條一出現(xiàn),編輯框就錯位了:

jQueryv3.3.1的BUG如何解決

而這個問題,在使用 jQuery v1.12.4 時是不存在的!

分析問題

經(jīng)過一段時間的調(diào)試,最終確定這是最新版 jQuery v3.3.1 的一個BUG,出現(xiàn)這個問題需滿足如下條件:

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: 0;
  background-color: green;
}

table td {
  padding: 0;
  height: 50px;
  color: #fff;
  vertical-align: top;
}

為了更直觀的描述問題,我們用不同的背景色標識外層的容器(.container)和內(nèi)部的表格(table)。

JavaScript代碼塊:

$(function() {
    var tdPosition = $('#theTD').position();
    $('#result').html('top:' + tdPosition.top + ' left:' + tdPosition.left);
});

按照正常的思維模式,上面的 theTD 的相對位置應該是相對 .container 的偏移量(因為 .container 是 td 的第一個遇到的相對定位的父元素)。 

因為 .container 設置了 50px 的內(nèi)邊距,表格每行的高度為 50px,所以 theTD 距離 .container 的垂直高度應該是 100px。

所以我們期望的輸出結果應該是:

top:100 left:50

但是結果真的如此嗎?我創(chuàng)建了兩個示例,分別是 引用 jQuery v1.9.1 的示例 和 引用 jQuery v3.3.1 的示例,得到的結果如下所示:

jQueryv3.3.1的BUG如何解決

jQueryv3.3.1的BUG如何解決

可見,在 jQuery v3.3.1 中,獲取表格中 td 節(jié)點的相對位置(position)得到的結果并不是我們想要的。那這個值到底是什么?

top: 50 left:0

解決問題

經(jīng)過認真分析,我認為這個值是 td 相對外部 table 節(jié)點的偏移量,而不是相對于第一個浮動父節(jié)點的位置(position: relative / absolute)。

曾經(jīng)一度我對 position() 和 offset() 的確切含義產(chǎn)生了懷疑,難道是我理解錯了?后來發(fā)現(xiàn)我的理解沒有問題:

.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 節(jié)點時出了差錯:

打開瀏覽器的調(diào)試窗口,我輸入如下代碼:

$('#theTD').offsetParent()

jQueryv3.3.1的BUG如何解決

可見,通過 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));
    
});

jQueryv3.3.1的BUG如何解決

看著好像是正確的,后來測試發(fā)現(xiàn)遇到嵌套表格就不行了,如下示例:

<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: 0;
  background-color: green;
}

table td {
  padding: 0;
  height: 50px;
  color: #fff;
  vertical-align: top;
}

jQueryv3.3.1的BUG如何解決

第二次嘗試

一計不成,再生一計。既然 table 的 position 出問題,那么 div 的 position 應該是正常的吧。這次我就來在 td 里面動態(tài)創(chuàng)建一個 div 節(jié)點怎么樣?

$(function() {
  var tmpDiv = $('<div />').prependTo($('#theTD'));
  var tdPosition = tmpDiv.position();
  tmpDiv.remove();
  
    $('#result').html('top:' + tdPosition.top + ' left:' + tdPosition.left);
});

jQueryv3.3.1的BUG如何解決

看著好像沒有問題,可以問題依舊,當設置 td 的 vertical-align: middle 時,問題暴露出來了,因為此時 td 內(nèi)的 div 是居中顯示的:

jQueryv3.3.1的BUG如何解決

第三次嘗試

就在我一籌莫展時,我忽然想到前面的 offsetParent() 函數(shù),這個函數(shù)能獲取正確的父節(jié)點。既然 position() 函數(shù)有問題,我何不嘗試 offset() 函數(shù)。

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 相減,得到的結果是否我們所需要的呢?

jQueryv3.3.1的BUG如何解決

不錯,正是我們所需要的。因為這個邏輯判斷很簡單,和是否表格嵌套沒關系,所以測試下第一次嘗試失敗的情況:

jQueryv3.3.1的BUG如何解決

 Bingo! 一切正常。此問題圓滿解決!

真是的jQuery的BUG嗎?

想想就不可思議,一個被全球用戶使用的公共JavaScript居然有這樣的BUG,難道就沒人發(fā)現(xiàn)么?

網(wǎng)上搜索了一圈,看起來我多慮了,早就有用戶提出這個問題:

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 native offsetParent 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 核心開發(fā)團隊給出的答案,大意是說 offsetParent 這個節(jié)點屬性指的是這樣一個父節(jié)點:

1. 節(jié)點是非靜態(tài)的,也就是擁有 position: relative / absolute / fixed 樣式

2. 節(jié)點是 table, th 或者 td

哈,這么多年過去了,我居然第一次聽說 offsetParent 還有相對于 td,th,table這個說法,盡管這個td,th,table節(jié)點是 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:

jQueryv3.3.1的BUG如何解決

Firefox:

jQueryv3.3.1的BUG如何解決

Edge:

jQueryv3.3.1的BUG如何解決

IE11(由于IE11打不開jsfiddle網(wǎng)站,我們單獨創(chuàng)建了一個頁面):

jQueryv3.3.1的BUG如何解決

甚至IE9也是這樣的:

jQueryv3.3.1的BUG如何解決

好吧,看來我真是孤陋而寡聞了。

jQuery 是在 v3.3.0 開始考慮到第二種情況的,但是 jQuery.offsetParent() 的定義沒有改變。這種不一致性本身就是一個BUG。

而不和之前的 jQuery v1.x, v2.x 乃至于 v3.3.0 之前的版本兼容,對于一個廣泛使用的公共庫而言,更應該算是一個BUG,或者至少提供兼容之間的方法。

考慮另一個更現(xiàn)實的問題:在實際應用中,我們?yōu)槭裁匆@取 td ,table 的 position() 呢?

不是為了拿獲取到的值去更新其他 td 或者 table 的 top/left 屬性!

而是為了拿獲取的值去更新其他相關 div 節(jié)點的 top/left 屬性,而 div 節(jié)點的 position() 是相對于 position: relative / absolute / fixed 父節(jié)點的,而非 td ,table 節(jié)點,這就一定會出問題。

所以,我們還是認定這是一個BUG。

但是 jQuery 官方貌似沒有修正這個問題的意思,而是可能在將來版本修改  jQuery.offsetParent() 的定義:

jQueryv3.3.1的BUG如何解決

但是jQuery你這樣做真的好么,都10多年了你都沒遵守標準,突然來個小版本號稱支持標準,搞的和之前的代碼不兼容,你讓之前的代碼情何以堪!

不管怎樣,我們有了自己的解決辦法。

感謝各位的閱讀,以上就是“jQueryv3.3.1的BUG如何解決”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對jQueryv3.3.1的BUG如何解決這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI