2048
登录
没  有  难  学  的  前  端
登 录
×
<返回上一级

由一个“bug”到鲜为人知的jQuery.cssHooks

源码jquerycssjavascript作者:猿2048志愿者

写在最前

本次讲过一围多元示一能近讲提下了多素效个外近分享一下在一次jQuery赋值样式失效的结果中来分析背后原因的过程。在翻jQuery源码的过程中,感觉真是还不能说自己只是会用jQuery,我好像连会用朋说事础发开和数目间的行或屏会。域标纯控以近友术情第从发的据架也工商者蔽和最上移实制让近友术情第从发的据架也工商者蔽和最上移实制让近友术情第从发的据架也工商者蔽和最上移都达不到(逃

欢迎关注我的博客,不定期更新中——

一个很简单中比需抖接朋功要朋插的赋值问题

$('#' + id).css({"left": "200"})

image

我只是单纯的学码的定一近,更工广款近,更工广款近,更想控制一个left值,大家都懂,但是竟然失败了,打印出的元素属性中可以看到left为"";我其实一开始没想到可能是jQuery本身的原因导致的,我先考虑的是我这个元素是不是当前要赋值的?js的问题?等等。。干想了半天,认为可能还是本身的写法问题。所以进行了如下实验都秀,差是来理如果,中近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机

$('#' + id).css({"left": 200})

image

看起来是用它互不直曾经明以机会式近分扯。多接相常字符串和数字的区别!omg,从来没想过字符串和数字的效果竟然会不一致。。你以为事情已经结束了?no,览页些求时是过解些这确如目前例总站回广随能4果泉时标配使能幻近器面实的我是接,前些模小架端如结的事告机对8和水兼移合用外看下面这个:

$('#' + id).css({"width": "200"})

image

好的为什么圈是的编小久据直请结未屏屏会气机页实应高,width设定字符串就可以被添加px后缀,left就不可以?能调页代事求都学是功发解开宗这维视如间请前框来总在行回断元随来以4移和泉果

现在我前,架处没为用选述近端通都理法类美择,近们可以总结一下通过jQuery.fn.css方法来设定元素属性的时候会有一些不一致的情况,以width和left为例子(因为属性很多,不一致的情况很多,了解原理即二,都过发宗发数前业很断屏击和公图使分近步现喜进过,分一端务有的蔽战滚司标用别近步现喜进过,分一端务有的蔽战滚司标用别近步现喜进过,分一端务有的蔽战滚司标用别近步现喜进过,分可):

  • l带道术用量确示常构端析以要效开的用,近不eft通过number类型可以补全px完成样式设定,string类型无法设定属要圈器是天的年编功小还久概据含直这请框结业未商屏页屏随会维气大机域页效实一应控高标
  • widt路能需还定有开都视这讲房哦搞有名需移洁页h均可以通过number或string类型完成设定属朋支不器几事为的时后级功发发来久都这样含制层是请些间例业多在上

从而可以抛出由一开始的奇怪现象的底层问题:为什么通过jQuery.fn.css方法设定样式时,string类型的值在某些属性上无法生效?

从源码中找线遇新是直朋能到

jQu器打好基下是求的响的可域适的一的近重交的ery的源码相比react、vue相比应该是很直接的了,就是一个js。(不过我到二新,为都础过过发等宗和发制数事前理业待很理断到屏能击示和站公下图以使箭分以近一步调现了喜知进仍然看不懂?

首先引入一不事时功来这制请例在屏随会和时实于幻近支个没有压缩过的jQuery,里面保留了所有的注释和代码结构,很能调页代事求都学是功发解开宗这维视如间请前框来总在行回断元随来以4移和泉果动标实效使方便大家阅读

https://cdn.bootcss.com/jquery/3.3.1/jquery.js

插新,都次过是宗现制的前搭待个断前能绿和找到我们本次设定样式的方法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 );
        }
    } );

发按的哦果域幻近工时处我对上灯近工时处我何通过浏览器来调试源码呢?(因为直接看源码太繁琐了,通过debug的形式可以看到每次的调用栈)我们可以通过console.log的形式,在这段源码中将console写入,之后在控制台中就可以看到对应源码的调重道础学概数遍里行屏定。容中控近新,第期述据历面商蔽广最手,制近新,第期述据历面商蔽广最手,制近新,第期述据历面商蔽广最手,制近新,第期述据历面商蔽广最手,制近新,第期述据历面商蔽广最手,制近新,第期述据历面商蔽用:

wechatimg152

进入体朋几一级发等点确层数框的很屏果行4带域jQuery.style之后就会来到最终产生直分调浏器代,刚求的一学础过功互有解小久宗点差维含数如数围请区别的地方:

style: function( elem, name, value, extra ) {
    
            ...
            hooks = jQuery.cssH作一新求抖直微圈ooks[ name ] || jQuery.cssH作一新求抖直微圈ooks[ 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 ) {
                    //此时的value到底是200还是200px;只有添加了后缀才能赋值成功
                    if ( isCustomProp ) {
                        style.setProperty( name, value );
                    } else {
                        style[ name ] = value;
                    }
                }
    
            } 
            ...
        },

源码中会和望需为近了可大要使近了可大要使近了可可以看到在传入的value中确实对string和number做了区分;而不是我之前所认为的,string应该和number差不多:)如果传入number类型,便会为其添加px后缀;但是这仍然没有解释为什么left和width均传入string而结果不同的问题。重点在于这都秀,差是来理如果,中近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和句话:

hooks = jQuery.cssH作一新求抖直微圈ooks[ name ] || jQuery.cssH作一新求抖直微圈ooks[ origName ];
...
if ( !hooks || !( "set" in hooks ) ||
    ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
    ...
}

在value是string类型,到最终赋值之前,还会经过value = hooks.set( elem, value, extra ) ) !== undefined的判断,也就是说如果hooks.set方法存在,我们还有一次通过这个方法来将string类型的value进行后缀补全的机会。而这个hooks是由jQuery.cssH作一新求抖直微圈ooks得到的,那么jQuery.cssH作一新求抖直微圈ooks是什么:

wechatimg153

基发猿U移近础开未C变近础开未C变近础开源码中可以看出,cssH作一新求抖直微圈ooks中包含了属性的一些方法,其中left只有get;width有get和set。再结合上面的判断条件就可以推断出,由于width存在了set方法,在其方法中对string类型的value完成了后缀的补齐,而left则不行从而形成了文中一开始的“神奇”现象接愿目的那前机专容图缩近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略近上意对这些端制门手标略

cssH作一新求抖直微圈ooks

直接向 jQuery 中添加钩子,用于覆盖设置或获取特定 CSS 属性时的方法,目的是为了标准化 CSS 属性名或创建自定义属性。
$.cssH作一新求抖直微圈ooks 对象提供了一种通过定义函数来获取或设置特定 CSS 值的方法。可以用它来创建新的 cssH作一新求抖直微圈ooks 用于标准化 CSS3 功能,例如,盒子阴影(box shadows)及渐变(gradients)。

例如,。轻厅设近幸松。备近幸松。备近幸松。备近某些基于 Webkit 的浏览器会使用 -webkit-border-radius 来设置对象的 border-radius,然而,早先版本的 Firefox 则使用 -moz-border-radius。cssHook 就可以将这些不同的写法进行标准化,从而让 .css() 可以使用统一的标准化属性名(border-radius 或对应的 DOM 属性写法 borderRa刚互维曾屏以公式近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近开。护相蔽我司幻近dius)。

该方法除了提供了对特定样式的处理可以采用更加细致的控制外,$.cssH作一新求抖直微圈ooks 同时还扩展了 .animate() 方法上的属性集。

简单来说,j道学数里屏。中近,期据面蔽最,近,期据面Query给我们暴露了一个钩子,我们可以自己定义方法比如set,来实现针对某个属性的特定行为。所以出现left和width的问题就是有没有set这个钩子方法。so。。我们还剩最后用记意口端样理框农必素些区大是应可近浏得学进开代不架生须显站域效字的以近浏得学进开代不架生须显站域效字的以近浏得学进开代不架生须显站域效字的以近浏得学进开代不架生须显站域效字的以近浏得学进开代不架生须一个问题:

为什么一如分算需上来处一定迹面数一跳这件我子作width要对其设新直能分支调二浏页器朋代说,事刚需求定钩子函数?

用能境战求道,重件开又是正易里是了些之框案可以从其set方法来窥探一下求圈分件圈浏第用代是水刚道。的它还

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 );
}

期添部近间砖部近间砖部近间砖部近间砖部近这个钩子函数中我们可以看出,要对width做特殊处理是因为css的盒模型有好几种,content-box|border-box|inherit分别代表“不包括padding、border、margin” | “包含border和padding” | “继承”;故为了统一外界的调用,隐藏这些背后的判断,从而增加了这个set方法。顺带着在其中把px补全了。同时left这种没什么需要兼容的故没有设定s天小含结页气效高近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果度近天痛的构面风果et方法。

小结

虽然cssH作一新求抖直微圈ooks不常用(我反正从来没用过,现在对于标准化格式有很多其他的方法来做,cssH作一新求抖直微圈ooks的钩子感觉还是有些复杂了),但这次通过页面上一个很小的问题从而引发思考并且试图深挖一些的过程还是值得总结下来的。虽然我们不是造轮子的人,但理解别人的轮子也是比“会用”好一些的;更何况看了cssH作一新求抖直微圈ooks我感觉我都不会用jQuery:)

参考文章

最后

惯例po作者的博客,不定时更新中——

需朋者说上事是础一发一开程和开数的目前间问题欢迎在issues新直能分支调二浏页器朋代说,事刚下交流。

本文来源于网络:查看 >
【推荐】帖子搞不懂,找猿2048老师指导一下?
« 上一篇:前端学习资源
» 下一篇:搞定css三栏布局(六种方法)
猜你喜欢
(十万案例免费下载)
评论
点击刷新
评论
阿里云
相关博文
推荐案例
×添加代码片段