成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

jQuery 源碼系列(十)hooks 的原理

nihao / 3066人閱讀

摘要:歡迎來(lái)我的專(zhuān)欄查看系列文章。算是中一個(gè)非??梢越梃b的用法,以前聽(tīng)到這個(gè)概念是非常恐懼的,當(dāng)看了源碼,弄懂原理之后,發(fā)現(xiàn)超級(jí)有意思。參考源碼分析鉤子機(jī)制屬性操作源碼學(xué)習(xí)本文在上的源碼地址,歡迎來(lái)。

歡迎來(lái)我的專(zhuān)欄查看系列文章。

hooks 在英語(yǔ)中的意思表示鉤子或掛鉤,在 jQuery 中也有 hooks 這么一個(gè)概念,它的功能在考慮到一些兼容性和其它特殊情況的條件下,優(yōu)先考慮這些特殊情況,而后才去用普通的方法處理,這種說(shuō)法還是比較形象的。

hooks 的使用非常用技術(shù)含量,可以支撐在原來(lái)的基礎(chǔ)上擴(kuò)展,而對(duì)于接口則無(wú)需改變,舉個(gè)例子,像 fn.css() 這個(gè)函數(shù)我們都是非常熟悉的了,拿來(lái)就用,而不需要考慮瀏覽器的兼容性,這里的兼容性包括 border-radius 兼容,使用的時(shí)候不需要在前面加上 -webkit- 瀏覽器標(biāo)識(shí)。而 css 函數(shù)的內(nèi)部則是借助 $.cssHooks()來(lái)實(shí)現(xiàn)這種“鉤子”的效果的,擴(kuò)展的時(shí)候,也是在這個(gè)對(duì)象上進(jìn)行擴(kuò)展。

先來(lái)說(shuō)說(shuō) attr 和 prop

不急著上來(lái)就談 hooks,先來(lái)看看 hooks 涉及到的應(yīng)用。一個(gè)典型的應(yīng)用就是 fn.attrfn.prop,這兩個(gè)原型函數(shù)的作用是用來(lái)給 jQuery 對(duì)象綁定元素的,如果不了解,可以參考這兩個(gè)鏈接,attr,prop。

雖然它們都是添加屬性,卻是不同的方式,其中,attr 是把屬性放到 html 中(實(shí)際上是 elem.attributes 屬性),而 prop 是把屬性添加到 dom 對(duì)象上,可以通過(guò) [.] 來(lái)讀取。

那么什么叫做 html 中?就是我們常說(shuō)的 data- 數(shù)據(jù):

var body = $("body");
body.attr("data-name","body");
// 
body.data("name"); //"body"

attr 方法是對(duì)應(yīng)于 jQuery 中的方法,而內(nèi)部是通過(guò) setAttribute,getAttribute 這種低級(jí) api 來(lái)實(shí)現(xiàn)的,而且在 dom 對(duì)象的 attributes 屬性上是可以找到綁定值的,所以 attr 和 prop 是兩種不同的方法。

這兩個(gè)函數(shù)有四個(gè)功能,分別包括讀取和設(shè)置,如果參數(shù)只有一個(gè),表示讀(如果參數(shù)是 Object 另外考慮),參數(shù)為兩個(gè),表示寫(xiě)。

當(dāng)然,除此之外,還有 removeAttr 和 removeProp 方法,源碼如下:

jQuery.fn.extend({
  attr: function (name, value) {
    return access(this, jQuery.attr, name, value, arguments.length > 1);
  },
  removeAttr: function (name) {
    return this.each(function () {
      jQuery.removeAttr(this, name);
    });
  },
  prop: function (name, value) {
    return access(this, jQuery.prop, name, value, arguments.length > 1);
  },
  removeProp: function (name) {
    return this.each(function () {
      delete this[jQuery.propFix[name] || name];
    });
  }
})
access 方法

先看 attr 和 prop,都是通過(guò) access 函數(shù),至少傳入的參數(shù)不同,一個(gè)是 jQuery.attr,一個(gè)是 jQuery.prop。來(lái)看看 access:

var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
  var i = 0,
    len = elems.length,
    bulk = key == null;

  // 參數(shù)為對(duì)象,一次性設(shè)置多個(gè)值
  if ( jQuery.type( key ) === "object" ) {
    chainable = true;
    for ( i in key ) {
      access( elems, fn, i, key[ i ], true, emptyGet, raw );
    }

  // 設(shè)置一個(gè)值
  } else if ( value !== undefined ) {
    chainable = true;

    if ( !jQuery.isFunction( value ) ) {
      raw = true;
    }
    
    // key 為 null 的情況
    if ( bulk ) {

      if ( raw ) {
        fn.call( elems, value );
        fn = null;

      // value 為 function
      } else {
        bulk = fn;
        fn = function( elem, key, value ) {
          return bulk.call( jQuery( elem ), value );
        };
      }
    }

    // 函數(shù)執(zhí)行在這里
    if ( fn ) {
      for ( ; i < len; i++ ) {
        fn(
          elems[ i ], key, raw ?
          value :
          value.call( elems[ i ], i, fn( elems[ i ], key ) )
        );
      }
    }
  }

  if ( chainable ) {
    // 寫(xiě)情況的返回值
    return elems;
  }

  // Gets
  if ( bulk ) {
    return fn.call( elems );
  }
  // 這個(gè)返回值是比較熟悉的,即 get
  return len ? fn( elems[ 0 ], key ) : emptyGet;
}

access 不是今天的重點(diǎn),函數(shù)不是很難,源碼讀起來(lái)挺有意思。

attr 和 prop 源碼

來(lái)看看 jQuery.attr 和 jQuery.prop:

jQuery.attr = function (elem, name, value) {
  var ret, hooks, nType = elem.nodeType;

  // 對(duì)于 text, comment 和 attribute nodes 不處理
  if (nType === 3 || nType === 8 || nType === 2) {
    return;
  }

  // 如果連這個(gè)函數(shù)都不支持,還是用 prop 方法吧
  if (typeof elem.getAttribute === "undefined") {
    return jQuery.prop(elem, name, value);
  }

  // 先處理 hooks,優(yōu)先考慮非正常情況
  if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
    hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : undefined);
  }
  // value 為 underfined 的時(shí)候調(diào)用 remove
  if (value !== undefined) {
    if (value === null) {
      jQuery.removeAttr(elem, name);
      return;
    }
    // hooks.set
    if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
      return ret;
    }
    // 非 hooks 情況,正常 set
    elem.setAttribute(name, value + "");
    return value;
  }
  // hooks.get
  if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
    return ret;
  }
  // 正常 get 方法
  ret = jQuery.find.attr(elem, name);

  // Non-existent attributes return null, we normalize to undefined
  return ret == null ? undefined : ret;
}
jQuery.prop = function (elem, name, value) {
  var ret, hooks, nType = elem.nodeType;

  // Don"t get/set properties on text, comment and attribute nodes
  if (nType === 3 || nType === 8 || nType === 2) {
    return;
  }

  if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
    // Fix name and attach hooks
    name = jQuery.propFix[name] || name;
    hooks = jQuery.propHooks[name];
  }

  if (value !== undefined) {
    if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
      return ret;
    }

    return elem[name] = value;
  }

  if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
    return ret;
  }

  return elem[name];
}

可以看得出來(lái),jQuery.attrjQuery.prop 方法是真的非常像,但是如果你不懂 hooks,可能會(huì)有很不疑問(wèn),這個(gè)不急??梢钥偨Y(jié)出大致的處理流程:先判斷 dom 類(lèi)型,然后根據(jù)一些特殊情況,復(fù)制 hooks 參數(shù),這里的特殊條件為 (nType !== 1 || !jQuery.isXMLDoc(elem)),接著對(duì)于 set 和 get 方法判斷,通過(guò) value 值是否為 underfined,如果 hooks 中有,用 hooks 中提供的方法,沒(méi)有,就走正常流程。

初識(shí) hooks

已經(jīng)知道在哪里使用 hooks,那么 hooks 長(zhǎng)什么樣呢:

jQuery.extend({
  attrHooks: {
    // attrHooks 兼容 type 的低版本瀏覽器的情況
    type: {
      set: function( elem, value ) {
        if ( !support.radioValue && value === "radio" &&
          jQuery.nodeName( elem, "input" ) ) {
          var val = elem.value;
          elem.setAttribute( "type", value );
          if ( val ) {
            elem.value = val;
          }
          return value;
        }
      }
    }
  },
  propHooks: {
    tabIndex: {
      get: function( elem ) {
        ...
      }
    }
  }
})
// jQuery 內(nèi)部擴(kuò)展
// 對(duì)于不支持 selected 的情況
if(!support.optSelected){
  jQuery.propHooks.selected = {
    get: function(){
      ...
    },
    set: function(){

    }
  }
}

在 attr 的 attrHooks 中,用來(lái)處理的特殊情況是 name=type 的情況,或許是這種情況,type 綁定不到 html 中。在 prop 的 propHooks 中,處理的特殊情況是 tabIndex,下面還擴(kuò)展了一個(gè) selected 方法,如果瀏覽器不支持 select,就建一個(gè) hooks。

所以一個(gè)基本的 Hooks(jQuery 內(nèi)部的)應(yīng)該長(zhǎng)這樣:

jQuery.extend({
  nameHooks: {
    get: function(){
      ...
    },
    set: function(){
      ...
    },
    other: function(){
      ...
    }
  }
})

get 和 set 是非必需的,這是因?yàn)?attr 和 prop 的特殊性造成的,在看一個(gè)例子 jQuery.fn.val,val 的介紹 jQuery.val,val 也有一個(gè) valHooks 與之對(duì)應(yīng):

jQuery.extend({
  valHooks: {
    option: {
      get: function(){...}
    },
    select: {
      get: function(){...},
      set: function(){...}
    }
  }
})

valHooks 和之前略有不同,又多了一層,但基本思路是一致的。

外部擴(kuò)展 Hooks

jQuery 內(nèi)部的 hooks 功能是非常強(qiáng)大的,不過(guò)令人感覺(jué)欣慰的是可以在外部擴(kuò)展。

比如有一個(gè)問(wèn)題,我們之前解釋 attr 的時(shí)候,知道它可以添加 html 的 attribute,但有一些固有的,比如 class,我們就是想在它上面添加,但又不能影響原有的 class 屬性,可以這樣來(lái)修改:

jQuery.attrHooks.class = {
  // 這里的參數(shù)順序后面兩個(gè)是相反的
  set: function(elem, value){
    return $(elem).attr("class-sp", value);
  },
  get: function(elem){
    return $(elem).attr("class-sp");
  }
}

//測(cè)試
body.attr("class","test");
// 
body.attr("class"); // "test"

perfect!

總結(jié)

Hooks 講這么多,應(yīng)該就 ok 了。Hooks 算是 jQuery 中一個(gè)非??梢越梃b的用法,以前聽(tīng)到這個(gè)概念是非??謶值?,當(dāng)看了源碼,弄懂原理之后,發(fā)現(xiàn)超級(jí)有意思。

仍然有不足,比如 jQuery 中一個(gè)非常有重量級(jí)的 cssHooks 就沒(méi)有提到,還是腳踏實(shí)地吧。

參考

jQuery 2.0.3 源碼分析 鉤子機(jī)制 - 屬性操作
jQuery Hooks
jQuery.cssHooks
jQuery.val
jQuery hooks源碼學(xué)習(xí)

本文在 github 上的源碼地址,歡迎來(lái) star。

歡迎來(lái)我的博客交流。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81781.html

相關(guān)文章

  • jQuery 源碼系列三)事件處理源碼

    摘要:專(zhuān)門(mén)為事件建立一個(gè)有問(wèn)題,直接退出如果是一個(gè)事件處理對(duì)象,且有屬性。參考源碼分析事件體系結(jié)構(gòu)解密事件核心綁定設(shè)計(jì)一解密事件核心委托設(shè)計(jì)二本文在上的源碼地址,歡迎來(lái)。 歡迎來(lái)我的專(zhuān)欄查看系列文章。 通過(guò)前面一章對(duì)于 addEvent 庫(kù)的介紹,它的兼容性超級(jí)棒,據(jù)說(shuō)對(duì)于 IE4、5 都有很好的兼容性,這和 jQuery 的原理是一致的,而在 jQuery 中,有一個(gè)對(duì)象與其相對(duì)應(yīng),那就是...

    劉厚水 評(píng)論0 收藏0
  • 由一個(gè)“bug”到鮮為人知jQuery.cssHooks

    摘要:干想了半天,認(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)注我的博客,不定期更...

    ernest.wang 評(píng)論0 收藏0
  • 由一個(gè)“bug”到鮮為人知jQuery.cssHooks

    摘要:干想了半天,認(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)注我的博客,不定期更...

    malakashi 評(píng)論0 收藏0
  • jQuery源碼解析之$.queue()、$.dequeue()和jQuery.Callbacks(

    摘要:作為此時(shí)不存在,直接從數(shù)據(jù)緩存中獲取并返回。作用是觸發(fā)中的回調(diào)函數(shù),的表示只讓觸發(fā)一次后,就需要清理,表示是將清空成空數(shù)組還是空字符。 showImg(https://segmentfault.com/img/remote/1460000019558449); 前言:queue()方法和dequeue()方法是為 jQuery 的動(dòng)畫(huà)服務(wù)的,目的是為了允許一系列動(dòng)畫(huà)函數(shù)被異步調(diào)用,但不...

    itvincent 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<