摘要:干想了半天,認(rèn)為可能還是本身的寫(xiě)法問(wèn)題。對(duì)象提供了一種通過(guò)定義函數(shù)來(lái)獲取或設(shè)置特定值的方法。簡(jiǎn)單來(lái)說(shuō),給我們暴露了一個(gè)鉤子,我們可以自己定義方法比如,來(lái)實(shí)現(xiàn)針對(duì)某個(gè)屬性的特定行為。
寫(xiě)在最前
本次分享一下在一次jQuery賦值樣式失效的結(jié)果中來(lái)分析背后原因的過(guò)程。在翻jQuery源碼的過(guò)程中,感覺(jué)真是還不能說(shuō)自己只是會(huì)用jQuery,我好像連會(huì)用都達(dá)不到(逃
歡迎關(guān)注我的博客,不定期更新中——
一個(gè)很簡(jiǎn)單的賦值問(wèn)題$("#" + id).css({"left": "200"})
我只是單純的想控制一個(gè)left值,大家都懂,但是竟然失敗了,打印出的元素屬性中可以看到left為"";我其實(shí)一開(kāi)始沒(méi)想到可能是jQuery本身的原因?qū)е碌模蚁瓤紤]的是我這個(gè)元素是不是當(dāng)前要賦值的?js的問(wèn)題?等等。。干想了半天,認(rèn)為可能還是本身的寫(xiě)法問(wèn)題。所以進(jìn)行了如下實(shí)驗(yàn):
$("#" + id).css({"left": 200})
看起來(lái)是字符串和數(shù)字的區(qū)別!omg,從來(lái)沒(méi)想過(guò)字符串和數(shù)字的效果竟然會(huì)不一致。。你以為事情已經(jīng)結(jié)束了?no,看下面這個(gè):
$("#" + id).css({"width": "200"})
好的為什么,width設(shè)定字符串就可以被添加px后綴,left就不可以??
現(xiàn)在我們可以總結(jié)一下通過(guò)jQuery.fn.css方法來(lái)設(shè)定元素屬性的時(shí)候會(huì)有一些不一致的情況,以width和left為例子(因?yàn)閷傩院芏啵灰恢碌那闆r很多,了解原理即可):
left通過(guò)number類型可以補(bǔ)全px完成樣式設(shè)定,string類型無(wú)法設(shè)定屬性
width均可以通過(guò)number或string類型完成設(shè)定屬性
從而可以拋出由一開(kāi)始的奇怪現(xiàn)象的底層問(wèn)題:為什么通過(guò)jQuery.fn.css方法設(shè)定樣式時(shí),string類型的值在某些屬性上無(wú)法生效?
從源碼中找線索jQuery的源碼相比react、vue相比應(yīng)該是很直接的了,就是一個(gè)js。(不過(guò)我仍然看不懂?
首先引入一個(gè)沒(méi)有壓縮過(guò)的jQuery,里面保留了所有的注釋和代碼結(jié)構(gòu),很方便大家閱讀
https://cdn.bootcss.com/jquery/3.3.1/jquery.js
先找到我們本次設(shè)定樣式的方法jQuery.fn.css:
jQuery.fn.extend( { css: function( name, value ) { return access( this, function( elem, name, value ) { var styles, len, map = {}, i = 0; if ( Array.isArray( name ) ) { styles = getStyles( elem ); len = name.length; for ( ; i < len; i++ ) { map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); } return map; } return value !== undefined ? jQuery.style( elem, name, value ) : jQuery.css( elem, name ); }, name, value, arguments.length > 1 ); } } );
如何通過(guò)瀏覽器來(lái)調(diào)試源碼呢?(因?yàn)橹苯涌丛创a太繁瑣了,通過(guò)debug的形式可以看到每次的調(diào)用棧)我們可以通過(guò)console.log的形式,在這段源碼中將console寫(xiě)入,之后在控制臺(tái)中就可以看到對(duì)應(yīng)源碼的調(diào)用:
進(jìn)入jQuery.style之后就會(huì)來(lái)到最終產(chǎn)生區(qū)別的地方:
style: function( elem, name, value, extra ) { ... hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; if ( value !== undefined ) { type = typeof value; if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { value = adjustCSS( elem, name, ret ); type = "number"; } ... if ( type === "number" ) { value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); } ... if ( !hooks || !( "set" in hooks ) ||( value = hooks.set( elem, value, extra ) ) !== undefined ) { //此時(shí)的value到底是200還是200px;只有添加了后綴才能賦值成功 if ( isCustomProp ) { style.setProperty( name, value ); } else { style[ name ] = value; } } } ... },
源碼中可以看到在傳入的value中確實(shí)對(duì)string和number做了區(qū)分;而不是我之前所認(rèn)為的,string應(yīng)該和number差不多:)如果傳入number類型,便會(huì)為其添加px后綴;但是這仍然沒(méi)有解釋為什么left和width均傳入string而結(jié)果不同的問(wèn)題。重點(diǎn)在于這句話:
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; ... if ( !hooks || !( "set" in hooks ) || ( value = hooks.set( elem, value, extra ) ) !== undefined ) { ... }
在value是string類型,到最終賦值之前,還會(huì)經(jīng)過(guò)value = hooks.set( elem, value, extra ) ) !== undefined的判斷,也就是說(shuō)如果hooks.set方法存在,我們還有一次通過(guò)這個(gè)方法來(lái)將string類型的value進(jìn)行后綴補(bǔ)全的機(jī)會(huì)。而這個(gè)hooks是由jQuery.cssHooks得到的,那么jQuery.cssHooks是什么:
從源碼中可以看出,cssHooks中包含了屬性的一些方法,其中l(wèi)eft只有g(shù)et;width有g(shù)et和set。再結(jié)合上面的判斷條件就可以推斷出,由于width存在了set方法,在其方法中對(duì)string類型的value完成了后綴的補(bǔ)齊,而left則不行從而形成了文中一開(kāi)始的“神奇”現(xiàn)象。
cssHooks直接向 jQuery 中添加鉤子,用于覆蓋設(shè)置或獲取特定 CSS 屬性時(shí)的方法,目的是為了標(biāo)準(zhǔn)化 CSS 屬性名或創(chuàng)建自定義屬性。
$.cssHooks 對(duì)象提供了一種通過(guò)定義函數(shù)來(lái)獲取或設(shè)置特定 CSS 值的方法。可以用它來(lái)創(chuàng)建新的 cssHooks 用于標(biāo)準(zhǔn)化 CSS3 功能,例如,盒子陰影(box shadows)及漸變(gradients)。例如,某些基于 Webkit 的瀏覽器會(huì)使用 -webkit-border-radius 來(lái)設(shè)置對(duì)象的 border-radius,然而,早先版本的 Firefox 則使用 -moz-border-radius。cssHook 就可以將這些不同的寫(xiě)法進(jìn)行標(biāo)準(zhǔn)化,從而讓 .css() 可以使用統(tǒng)一的標(biāo)準(zhǔn)化屬性名(border-radius 或?qū)?yīng)的 DOM 屬性寫(xiě)法 borderRadius)。
該方法除了提供了對(duì)特定樣式的處理可以采用更加細(xì)致的控制外,$.cssHooks 同時(shí)還擴(kuò)展了 .animate() 方法上的屬性集。
簡(jiǎn)單來(lái)說(shuō),jQuery給我們暴露了一個(gè)鉤子,我們可以自己定義方法比如set,來(lái)實(shí)現(xiàn)針對(duì)某個(gè)屬性的特定行為。所以出現(xiàn)left和width的問(wèn)題就是有沒(méi)有set這個(gè)鉤子方法。so。。我們還剩最后一個(gè)問(wèn)題:
為什么width要對(duì)其設(shè)定鉤子函數(shù)?
答案可以從其set方法來(lái)窺探一下:
set: function( elem, value, extra ) { var matches, styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", subtract = extra && boxModelAdjustment( elem, dimension, extra, isBorderBox, styles ); // Account for unreliable border-box dimensions by comparing offset* to computed and // faking a content-box to get border and padding (gh-3699) if ( isBorderBox && support.scrollboxSize() === styles.position ) { subtract -= Math.ceil( elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - parseFloat( styles[ dimension ] ) - boxModelAdjustment( elem, dimension, "border", false, styles ) - 0.5 ); } // Convert to pixels if value adjustment is needed if ( subtract && ( matches = rcssNum.exec( value ) ) && ( matches[ 3 ] || "px" ) !== "px" ) { elem.style[ dimension ] = value; value = jQuery.css( elem, dimension ); } return setPositiveNumber( elem, value, subtract ); }
從這個(gè)鉤子函數(shù)中我們可以看出,要對(duì)width做特殊處理是因?yàn)閏ss的盒模型有好幾種,content-box|border-box|inherit分別代表“不包括padding、border、margin” | “包含border和padding” | “繼承”;故為了統(tǒng)一外界的調(diào)用,隱藏這些背后的判斷,從而增加了這個(gè)set方法。順帶著在其中把px補(bǔ)全了。同時(shí)left這種沒(méi)什么需要兼容的故沒(méi)有設(shè)定set方法。
小結(jié)雖然cssHooks不常用(我反正從來(lái)沒(méi)用過(guò),現(xiàn)在對(duì)于標(biāo)準(zhǔn)化格式有很多其他的方法來(lái)做,cssHooks的鉤子感覺(jué)還是有些復(fù)雜了),但這次通過(guò)頁(yè)面上一個(gè)很小的問(wèn)題從而引發(fā)思考并且試圖深挖一些的過(guò)程還是值得總結(jié)下來(lái)的。雖然我們不是造輪子的人,但理解別人的輪子也是比“會(huì)用”好一些的;更何況看了cssHooks我感覺(jué)我都不會(huì)用jQuery:)
參考文章jQuery源碼解析
jQuer中文文檔
最后慣例po作者的博客,不定時(shí)更新中——
有問(wèn)題歡迎在issues下交流。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107455.html
摘要:干想了半天,認(rèn)為可能還是本身的寫(xiě)法問(wèn)題。對(duì)象提供了一種通過(guò)定義函數(shù)來(lái)獲取或設(shè)置特定值的方法。簡(jiǎn)單來(lái)說(shuō),給我們暴露了一個(gè)鉤子,我們可以自己定義方法比如,來(lái)實(shí)現(xiàn)針對(duì)某個(gè)屬性的特定行為。 寫(xiě)在最前 本次分享一下在一次jQuery賦值樣式失效的結(jié)果中來(lái)分析背后原因的過(guò)程。在翻jQuery源碼的過(guò)程中,感覺(jué)真是還不能說(shuō)自己只是會(huì)用jQuery,我好像連會(huì)用都達(dá)不到(逃 歡迎關(guān)注我的博客,不定期更...
摘要:一在講之前,先弄清屬性是默認(rèn)值這是的值是是這是的值是因?yàn)槭前ǖ模话ā?上攵闹幸舶藢?duì)的判斷。 showImg(https://segmentfault.com/img/remote/1460000019169187); 一、在講之前,先弄清 boxSizing 屬性(1)box-sizing 是默認(rèn)值 content-box 這是divTwo $(#pTwo)...
摘要:本文已完結(jié),請(qǐng)看下文求索的動(dòng)畫(huà)快于嗎為何續(xù)本文源自對(duì)問(wèn)題動(dòng)畫(huà)性能優(yōu)于的原理是什么的回答。是這樣的嗎請(qǐng)看下文求索的動(dòng)畫(huà)快于嗎為何續(xù) 本文已完結(jié),請(qǐng)看下文: > 求索:GSAP的動(dòng)畫(huà)快于jQuery嗎?為何?/續(xù) 本文源自對(duì)問(wèn)題《GSAP js動(dòng)畫(huà)性能優(yōu)于jQuery的原理是什么?》的回答。GSAP是一個(gè)js動(dòng)畫(huà)插件,它聲稱20x faster than jQuery,是什么讓...
閱讀 291·2024-11-07 18:25
閱讀 130367·2024-02-01 10:43
閱讀 868·2024-01-31 14:58
閱讀 828·2024-01-31 14:54
閱讀 82768·2024-01-29 17:11
閱讀 3050·2024-01-25 14:55
閱讀 1985·2023-06-02 13:36
閱讀 3033·2023-05-23 10:26