升級到j(luò)Query?3.6.1遇見的一些坑以及應(yīng)對辦法
前言
項目因安全問題(jquery 早期版本存在XSS 漏洞),需要整體將 jQuery 從 1.7.2 升級到 3.6.1 。早前就因為 jQuery 的版本兼容性不佳,因此對于版本升級的事情,能拖則拖。但升級的事情,總歸是要做的,何況項目上因為甲方重視安全性,對于中等風險的安全也必須解決、規(guī)避,因此這回是硬著頭皮上了。
第一階段的問題,就是各種不兼容,各種不順。好在同事方法多,路子廣,找到了一個 jquery-migrate-3.4.0.js 文件,專治新舊版本兼容的 包,解決了大多數(shù)的問題。UI 界面總算能跑起來,能看得著了。
但是接下來,陸續(xù)遇到了幾個問題:
問題一:curCSS 方法找不到問題
解決方法:
jQuery.curCSS = function(element, prop, val) { return jQuery(element).css(prop, val); };
問題二:UI 布局錯誤,多處動態(tài)計算 div 占用的寬度、高度 進行自適應(yīng)布局的頁面都拉跨了。
仔細分析后發(fā)現(xiàn),罪魁禍首出現(xiàn)在 outerWidth 和 outerHeight 方法上。
這兩個方法,老版本 jquery (以 1.7.2 為例),例如調(diào)用 $("body").outerWidth() ,是可以返回整數(shù)值的。但是新版的方法,如果不帶參數(shù),則返回 元素的 jQuery 對象。 而由于程序?qū)⒅暈?int 參與計算,因此導(dǎo)致后續(xù)計算錯誤,界面布局拉跨也就難免了。
另外,老版本 jQuery 對于查找器搜索不到的情況,比如 $("#不存在的id").outerWidth() 是會返回 0 的,因為將一個不存在的元素的寬度視為0,也算是容錯的,但是新版本在這種情況下,直接返回 undefined,這也會造成一些代碼上的問題。
OK,知道原因,就可以有解決方案,如下:
var oldOuterWidth = jQuery.fn.outerWidth; jQuery.fn.outerWidth =function( ) { if (arguments.length <= 0) { arguments[0] = false; arguments.length = 1; } var result = oldOuterWidth.apply( this, arguments ) ; return result === undefined ? 0 : result; }; var oldOuterHeight = jQuery.fn.outerHeight; jQuery.fn.outerHeight =function( ) { if (arguments.length <= 0) { arguments[0] = false; arguments.length = 1; } var result = oldOuterHeight.apply( this, arguments ); return result === undefined ? 0 : result; };
問題三、添加 html 內(nèi)容 出錯,頁面元素 層次錯亂。
比如,有以下代碼:
$("body").append('<div><i class="c1" /><span>ok</span></div>');
在舊版 jQuery 當中,頁面內(nèi)容渲染得到:
<div><i class="c1"></i><span>ok</span></div>
但是在新版 jQuery 3.6.1 里得到的卻是:
<div><i class="c1"><span>hello</span></i></div>
兩者差別就是,針對 <i /> 的寫法,渲染有不同。
造成這個差異的原因是什么呢?我們拋開 jQuery ,試試原生 JS 的效果:
document.children[0].children[1].innerHTML = '<div><i class="c1" /><span>ok</span>';
結(jié)果渲染得到的與 jQuery 3.6.1 是一致的。也就是針對 <i /> 這種寫法,HTML 5 是不認的,因為 <i> 本身不屬于 HTML5 非閉合標簽 (所謂 非閉合標簽,是類似 <meta> <br> 這種,數(shù)量有限),則 渲染引擎 將 <i /> 視為未閉合。實際上 <element /> 的寫法,屬于 XHTML ,而不是 HTML5 的規(guī)范。
奇怪的是,為啥舊版 jQuery 我們用著就沒有問題,難道它在 append 方法里做了什么特殊處理?
排查了源碼,果不其然。如下:
// Convert html string into DOM nodes if ( typeof elem === "string" ) { if ( !rhtml.test( elem ) ) { elem = context.createTextNode( elem ); } else { // Fix "XHTML"-style tags in all browsers elem = elem.replace(rxhtmlTag, "<$1></$2>");
注釋上明確說了 Fix "XHTML"-style tags in all browsers 。哎,我們這些一直誤用的人啊,被老版本 jQuery 保護的太好了!
OK,為了確保此前的UI代碼能繼續(xù)使用,我們還是要得來個解決方案:
var oldAppend = jQuery.fn.append; jQuery.fn.append =function( ) { /** * 相關(guān)素材來自 jquery 1.7.2 */ var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig; if (arguments.length > 0 && typeof(arguments[0]) == "string" ) { var elem = arguments[0]; elem = elem.replace(rxhtmlTag, "<$1></$2>"); arguments[0] = elem; } return oldAppend.apply( this, arguments ); };
至此,遇到的不兼容問題基本都解決了。我們將包含前述問題的解決辦法,匯總到 以下 js 代碼里,需要的各位可以自取。
( function() { /** * 注意,以下代碼,應(yīng)確保 引用在 jquery 3.6.1, jquery-migrate-3.4.0.min.js,以及 jquery-ui-1.8.10.custom.min.js 等內(nèi)容之后,否則 * 相關(guān)的 代碼托管 可能會被取代 而 無效。 */ jQuery.curCSS = function(element, prop, val) { return jQuery(element).css(prop, val); }; /** * James add on 2022.11.24 , 相關(guān)代碼摘錄自 jquery 1.7.2 * 此 修復(fù)是為了 兼容 以下有關(guān)寫法,在 append 到 jquery 對象里時,能適應(yīng) 老版本的渲染邏輯。 * $.append("<div><i class='abc' /> <span>ttt</span></div>"); * 上述內(nèi)容,在 jquery 1.7.2 版本里,會被渲染為: * <div><i class='abc'></i><span>ttt</span></div> * * 而在 jquery 3.6.1 里,則會被渲染為: * <div><i class='abc'><span>ttt</span></i></div> * * 這是由于 在 舊版 jquery 里,針對 非閉合的標簽有過特定處理,而在 jquery 3.6.1 里則移除了這個做法。 * 因此直接在 element 的 innterHtml 里面寫入 <div><i class='abc' /> <span>ttt</span></div> 這個內(nèi)容, * 與 3.6.1 里面是一致的。 * * 所以根本上是不規(guī)范的 html 寫法,只是老版本 jquery 做了容錯,而新版本沒有容錯,因而導(dǎo)致問題。 * */ var oldAppend = jQuery.fn.append; jQuery.fn.append =function( ) { /** * 相關(guān)素材來自 jquery 1.7.2 */ var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig; if (arguments.length > 0 && typeof(arguments[0]) == "string" ) { var elem = arguments[0]; elem = elem.replace(rxhtmlTag, "<$1></$2>"); arguments[0] = elem; } return oldAppend.apply( this, arguments ); }; var oldOuterWidth = jQuery.fn.outerWidth; jQuery.fn.outerWidth =function( ) { if (arguments.length <= 0) { arguments[0] = false; arguments.length = 1; } var result = oldOuterWidth.apply( this, arguments ) ; return result === undefined ? 0 : result; }; var oldOuterHeight = jQuery.fn.outerHeight; jQuery.fn.outerHeight =function( ) { if (arguments.length <= 0) { arguments[0] = false; arguments.length = 1; } var result = oldOuterHeight.apply( this, arguments ); return result === undefined ? 0 : result; }; })();
注意,上述代碼在頁面中的引入,應(yīng)確保在 jquery 3.6.1, jquery-migrate-3.4.0.min.js,以及 jquery-ui-1.8.10.custom.min.js 等內(nèi)容之后,否則可能會被取代而無效。
總結(jié)
到此這篇關(guān)于升級到j(luò)Query 3.6.1遇見的一些坑以及應(yīng)對辦法的文章就介紹到這了,更多相關(guān)升級jQuery 3.6.1的坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
jQuery滾動監(jiān)聽實現(xiàn)商城樓梯式導(dǎo)航效果
這篇文章主要介紹了jQuery滾動監(jiān)聽,實現(xiàn)商城樓梯式導(dǎo)航,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03