升級(jí)到j(luò)Query?3.6.1遇見的一些坑以及應(yīng)對(duì)辦法
前言
項(xiàng)目因安全問題(jquery 早期版本存在XSS 漏洞),需要整體將 jQuery 從 1.7.2 升級(jí)到 3.6.1 。早前就因?yàn)?jQuery 的版本兼容性不佳,因此對(duì)于版本升級(jí)的事情,能拖則拖。但升級(jí)的事情,總歸是要做的,何況項(xiàng)目上因?yàn)榧追街匾暟踩裕瑢?duì)于中等風(fēng)險(xiǎn)的安全也必須解決、規(guī)避,因此這回是硬著頭皮上了。
第一階段的問題,就是各種不兼容,各種不順。好在同事方法多,路子廣,找到了一個(gè) jquery-migrate-3.4.0.js 文件,專治新舊版本兼容的 包,解決了大多數(shù)的問題。UI 界面總算能跑起來(lái),能看得著了。
但是接下來(lái),陸續(xù)遇到了幾個(gè)問題:
問題一:curCSS 方法找不到問題
解決方法:
jQuery.curCSS = function(element, prop, val) { return jQuery(element).css(prop, val); };
問題二:UI 布局錯(cuò)誤,多處動(dòng)態(tài)計(jì)算 div 占用的寬度、高度 進(jìn)行自適應(yīng)布局的頁(yè)面都拉跨了。
仔細(xì)分析后發(fā)現(xiàn),罪魁禍?zhǔn)壮霈F(xiàn)在 outerWidth 和 outerHeight 方法上。
這兩個(gè)方法,老版本 jquery (以 1.7.2 為例),例如調(diào)用 $("body").outerWidth() ,是可以返回整數(shù)值的。但是新版的方法,如果不帶參數(shù),則返回 元素的 jQuery 對(duì)象。 而由于程序?qū)⒅暈?int 參與計(jì)算,因此導(dǎo)致后續(xù)計(jì)算錯(cuò)誤,界面布局拉跨也就難免了。
另外,老版本 jQuery 對(duì)于查找器搜索不到的情況,比如 $("#不存在的id").outerWidth() 是會(huì)返回 0 的,因?yàn)閷⒁粋€(gè)不存在的元素的寬度視為0,也算是容錯(cuò)的,但是新版本在這種情況下,直接返回 undefined,這也會(huì)造成一些代碼上的問題。
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)容 出錯(cuò),頁(yè)面元素 層次錯(cuò)亂。
比如,有以下代碼:
$("body").append('<div><i class="c1" /><span>ok</span></div>');
在舊版 jQuery 當(dāng)中,頁(yè)面內(nèi)容渲染得到:
<div><i class="c1"></i><span>ok</span></div>
但是在新版 jQuery 3.6.1 里得到的卻是:
<div><i class="c1"><span>hello</span></i></div>
兩者差別就是,針對(duì) <i /> 的寫法,渲染有不同。
造成這個(gè)差異的原因是什么呢?我們拋開 jQuery ,試試原生 JS 的效果:
document.children[0].children[1].innerHTML = '<div><i class="c1" /><span>ok</span>';
結(jié)果渲染得到的與 jQuery 3.6.1 是一致的。也就是針對(duì) <i /> 這種寫法,HTML 5 是不認(rèn)的,因?yàn)?<i> 本身不屬于 HTML5 非閉合標(biāo)簽 (所謂 非閉合標(biāo)簽,是類似 <meta> <br> 這種,數(shù)量有限),則 渲染引擎 將 <i /> 視為未閉合。實(shí)際上 <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 保護(hù)的太好了!
OK,為了確保此前的UI代碼能繼續(xù)使用,我們還是要得來(lái)個(gè)解決方案:
var oldAppend = jQuery.fn.append; jQuery.fn.append =function( ) { /** * 相關(guān)素材來(lái)自 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)的 代碼托管 可能會(huì)被取代 而 無(wú)效。 */ 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 對(duì)象里時(shí),能適應(yīng) 老版本的渲染邏輯。 * $.append("<div><i class='abc' /> <span>ttt</span></div>"); * 上述內(nèi)容,在 jquery 1.7.2 版本里,會(huì)被渲染為: * <div><i class='abc'></i><span>ttt</span></div> * * 而在 jquery 3.6.1 里,則會(huì)被渲染為: * <div><i class='abc'><span>ttt</span></i></div> * * 這是由于 在 舊版 jquery 里,針對(duì) 非閉合的標(biāo)簽有過特定處理,而在 jquery 3.6.1 里則移除了這個(gè)做法。 * 因此直接在 element 的 innterHtml 里面寫入 <div><i class='abc' /> <span>ttt</span></div> 這個(gè)內(nèi)容, * 與 3.6.1 里面是一致的。 * * 所以根本上是不規(guī)范的 html 寫法,只是老版本 jquery 做了容錯(cuò),而新版本沒有容錯(cuò),因而導(dǎo)致問題。 * */ var oldAppend = jQuery.fn.append; jQuery.fn.append =function( ) { /** * 相關(guān)素材來(lái)自 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è)面中的引入,應(yīng)確保在 jquery 3.6.1, jquery-migrate-3.4.0.min.js,以及 jquery-ui-1.8.10.custom.min.js 等內(nèi)容之后,否則可能會(huì)被取代而無(wú)效。
總結(jié)
到此這篇關(guān)于升級(jí)到j(luò)Query 3.6.1遇見的一些坑以及應(yīng)對(duì)辦法的文章就介紹到這了,更多相關(guān)升級(jí)jQuery 3.6.1的坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
jQuery滾動(dòng)監(jiān)聽實(shí)現(xiàn)商城樓梯式導(dǎo)航效果
這篇文章主要介紹了jQuery滾動(dòng)監(jiān)聽,實(shí)現(xiàn)商城樓梯式導(dǎo)航,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03jQuery動(dòng)態(tài)改變多行文本框高度的方法
這篇文章主要介紹了jQuery動(dòng)態(tài)改變多行文本框高度的方法,結(jié)合實(shí)例形式分析了jQuery響應(yīng)鼠標(biāo)事件動(dòng)態(tài)修改頁(yè)面元素屬性的相關(guān)技巧,需要的朋友可以參考下2016-09-09jQuery+Ajax實(shí)現(xiàn)無(wú)刷新分頁(yè)
這篇文章主要介紹了jQuery+Ajax實(shí)現(xiàn)無(wú)刷新分頁(yè),本文使用的生成分頁(yè)的工具條是jquery.pagination.js,感興趣的小伙伴們可以參考一下2015-10-10jQuery中:last-child選擇器用法實(shí)例
這篇文章主要介紹了jQuery中:last-child選擇器用法,實(shí)例分析了:last-child選擇器功能、定義及匹配父元素的最后一個(gè)子元素用法技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2014-12-12