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

資訊專欄INFORMATION COLUMN

Zepto 源碼分析 3 - qsa 實(shí)現(xiàn)與工具函數(shù)設(shè)計(jì)

ctriptech / 814人閱讀

摘要:承接第一篇末尾內(nèi)容,本部分開始進(jìn)入主模塊,分析其設(shè)計(jì)思路與實(shí)現(xiàn)技巧下文代碼均進(jìn)行過重格式化,但代碼版本同第一部分內(nèi)容且入口函數(shù)不變的選擇器先從第一個(gè)與原型鏈構(gòu)造不直接相關(guān)的工具函數(shù)說起,觀察的設(shè)計(jì)思路。

承接第一篇末尾內(nèi)容,本部分開始進(jìn)入 zepto 主模塊,分析其設(shè)計(jì)思路與實(shí)現(xiàn)技巧(下文代碼均進(jìn)行過重格式化,但代碼 Commit 版本同第一部分內(nèi)容且入口函數(shù)不變):

Zepto 的選擇器 zepto.qsa()
  // Line 262
  zepto.qsa = function(element, selector) {
  };

先從第一個(gè)與原型鏈構(gòu)造不直接相關(guān)的工具函數(shù) qsa 說起,觀察 Zepto 的設(shè)計(jì)思路。

  // Line 28
  simpleSelectorRE = /^[w-]*$/,

    // Line 337
    var found,
      maybeID = selector[0] == "#",
      maybeClass = !maybeID && selector[0] == ".",
      nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
      isSimple = simpleSelectorRE.test(nameOnly);

函數(shù)開始部分先定義了幾個(gè) Bool 值,用以猜測是否可能為 idclass,此時(shí)如果可能是兩者中的一個(gè),那么去除標(biāo)記部分(. or #),否則取自身記為 nameOnly。simpleSelectorRE 用于測試可能被剝離了一次標(biāo)記部分的 selector 是否滿足是一般字符串的要求,如果不是,那么可能查詢目標(biāo)是多個(gè)條件組合(如 .class1.class2),后面直接放入原生的 querySelectorAll 方法查詢。

   // Line 268
   return element.getElementById && isSimple && maybeID // Safari DocumentFragment doesn"t have getElementById
      ? (found = element.getElementById(nameOnly))
        ? [found]
        : []

進(jìn)入包含一系列判斷的 return 階段,268 行中出現(xiàn)了一個(gè)兼容性注釋,由于前方的 maybeClass 定義中聲明了并非 id 所以此處不支持 getElementById 方法也將直接陷入原生的 querySelectorAll 方法。如果滿足查詢條件則發(fā)給原生 getElementById` 方法查詢,返回?cái)?shù)組方式的結(jié)果。

  // Line 6
    var undefined,
    key,
    $,
    classList,
    emptyArray = [],
    concat = emptyArray.concat,
    filter = emptyArray.filter,
    slice = emptyArray.slice,

      // Line 270
      : element.nodeType !== 1 &&
        element.nodeType !== 9 &&
        element.nodeType !== 11
      ? []
      : slice.call(
          isSimple && !maybeID && element.getElementsByClassName // DocumentFragment doesn"t have getElementsByClassName/TagName
            ? maybeClass
              ? element.getElementsByClassName(nameOnly) // If it"s simple, it could be a class
              : element.getElementsByTagName(selector) // Or a tag
            : element.querySelectorAll(selector) // Or it"s not simple, and we need to query all
        );

先參照 nodeType 判斷了根搜索元素類型,此處采用了和 id 相同的降級(jí)策略,并通過調(diào)用空數(shù)組上方法的方式調(diào)用了 Array.prototype 上的 slice 方法完成數(shù)組生成,整體 Zepto 庫實(shí)際上使用了相同的思想利用原型鏈給予 Z 對(duì)象上的操作方法。

Zepto 的幾個(gè)工具函數(shù)設(shè)計(jì)

Zepto 的數(shù)組與對(duì)象相關(guān)工具函數(shù)較相似于 Underscore.js 先行略去,著重列舉幾個(gè)有技巧的實(shí)現(xiàn):

類型相關(guān)工具函數(shù)的例子:

  // Line 29
  class2type = {},
  toString = class2type.toString,

  // Line 401
  // Populate the class2type map
  $.each(
    "Boolean Number String Function Array Date RegExp Object Error".split(" "),
    function(i, name) {
      class2type["[object " + name + "]"] = name.toLowerCase();
    }
  );

  // Line 65
  function type(obj) {
    return obj == null ? String(obj) :
      class2type[toString.call(obj)] || "object"
  }

工具函數(shù) type 中出現(xiàn)了 == 運(yùn)算符,此處利用了 null/undefined == null 的語言特性,并通過 String 包裝類進(jìn)行類型轉(zhuǎn)換得到其類型的字符串表示,如果并非為這兩種類型,則通過 class2type 的映射關(guān)系將其轉(zhuǎn)化為對(duì)應(yīng)的字符串類型名。

  // Line 78
  function likeArray(obj) {
    var length = !!obj && "length" in obj && obj.length,
      type = $.type(obj)

    return "function" != type && !isWindow(obj) && (
      "array" == type || length === 0 ||
        (typeof length == "number" && length > 0 && (length - 1) in obj)
    )
  }

工具函數(shù) likeArray 實(shí)際上給出了 Zepto 所認(rèn)為的數(shù)組形式,即:存在正 length 的 Number 型成員變量及 Key 值為 length - 1 的成員變量且并非是函數(shù)的對(duì)象。這樣定義可以使得迭代器模式可以使用,且恰好使用了未初始化的數(shù)組項(xiàng)為 undefined 類型的語言屬性。

判定元素與選擇器匹配性的函數(shù) matches

qsa() 函數(shù)類似,Zepto 還給出了一個(gè)類型匹配函數(shù) zepto.matches() 用于判斷某個(gè)元素是否與一個(gè)給定的選擇器匹配:

// Line 33
tempParent = document.createElement("div"),

  // Line 51
  zepto.matches = function(element, selector) {
  
    // 如果不滿足匹配的類型條件,那么返回結(jié)果為 False
    if (!selector || !element || element.nodeType !== 1) return false;
    
    // Element.prototype.matches() - 判定某個(gè)元素是否符合某個(gè)選擇器
    // https://dom.spec.whatwg.org/#dom-element-matches
    var matchesSelector =
      element.matches ||
      element.webkitMatchesSelector ||
      element.mozMatchesSelector ||
      element.oMatchesSelector ||
      element.matchesSelector;
    if (matchesSelector) return matchesSelector.call(element, selector);
    
    // 如果當(dāng)前瀏覽器未實(shí)現(xiàn) matches API,則降級(jí)為使用 qsa 函數(shù)完成
    // 如果父節(jié)點(diǎn)存在,則選取父節(jié)點(diǎn)進(jìn)行 qsa()
    // 如果父節(jié)點(diǎn)不存在,將目標(biāo)節(jié)點(diǎn)放入預(yù)定的父節(jié)點(diǎn)中,再在父節(jié)點(diǎn)上進(jìn)行 qsa() 檢驗(yàn)是否可以找到子節(jié)點(diǎn)
    // fall back to performing a selector:
    var match,
      parent = element.parentNode,
      temp = !parent;
    if (temp) (parent = tempParent).appendChild(element);
    match = ~zepto.qsa(parent, selector).indexOf(element);
    
    // 清除可能創(chuàng)建的父節(jié)點(diǎn)
    temp && tempParent.removeChild(element);
    return match;
  };

相似的構(gòu)造父級(jí)容器以查詢子級(jí)元素性質(zhì)思路在 Zepto 源代碼中多次出現(xiàn),例如對(duì)于另一個(gè)工具函數(shù) defaultDisplay 的實(shí)現(xiàn)中。

獲取當(dāng)前瀏覽器下某元素默認(rèn) display 值的 defaultDisplay() 函數(shù),由于 DOM 中的元素默認(rèn)樣式值實(shí)際上在用戶進(jìn)行更改前即為瀏覽器賦予節(jié)點(diǎn)類型的默認(rèn)值,因此查詢?cè)氐哪J(rèn)值可以變?yōu)椴樵兡彻?jié)點(diǎn)類型的默認(rèn)值:

// Line 8
elementDisplay = {}

  // Line 109
  function defaultDisplay(nodeName) {
    var element, display;
    // 如果全局 elementDisplay 對(duì)象中已經(jīng)緩存了查詢目標(biāo) nodeName 的結(jié)果那么直接查詢,否則陷入邏輯
    if (!elementDisplay[nodeName]) {
      
      // 創(chuàng)建一個(gè)同類型節(jié)點(diǎn),將其放入 body 下獲取它的實(shí)時(shí)計(jì)算值中的 display 屬性
      element = document.createElement(nodeName);
      document.body.appendChild(element);
      
      // 此處引用了 IE 模塊中的 getComputedStyle() 函數(shù)降級(jí)
      display = getComputedStyle(element, "").getPropertyValue("display");
      
      // 刪除用于取值的元素對(duì)象,如果元素的 display 值為 none 那么將其值設(shè)為 block
      // 此處將 none 置為 display 的原因?yàn)?$.fn.show() 函數(shù)中通過該函數(shù)獲取一個(gè)非隱藏型的默認(rèn)值
      element.parentNode.removeChild(element);
      display == "none" && (display = "block");
      
      // 緩存結(jié)果值至全局變量 elementDisplay
      elementDisplay[nodeName] = display;
    }
    return elementDisplay[nodeName];
  }
  
    // Line 574
    show: function() {
      return this.each(function() {
        this.style.display == "none" && (this.style.display = "");
        
        // defaultDisplay() 獲取值為 none 時(shí)設(shè)定為 block 的原因
        if (getComputedStyle(this, "").getPropertyValue("display") == "none")
          this.style.display = defaultDisplay(this.nodeName);
      });
     },
Zepto 加載擴(kuò)展的方法

本節(jié)末尾,簡單介紹一下擴(kuò)展 Zepto 的方法。在主模塊 Zepto 外,一個(gè)未默認(rèn)編譯的模塊 Selector 包含了擴(kuò)展原 qsa() 函數(shù)的實(shí)現(xiàn),進(jìn)入模塊代碼 src/selector.js,其結(jié)構(gòu)如下:

(function($) {
  var zepto = $.zepto,
    oldQsa = zepto.qsa,
    oldMatches = zepto.matches;

  zepto.qsa = function(node, selector) {
      // 擴(kuò)展的 zepto.qsa 實(shí)現(xiàn)
  };

  zepto.matches = function(node, selector) {
      // 擴(kuò)展的 zepto.matches 實(shí)現(xiàn)
  };
})(Zepto);

在實(shí)際編譯中只需將 Selector 在核心模塊后編譯即可替換原始的 qsa 函數(shù)與對(duì)應(yīng)的 matches 函數(shù),因此基于該思路的 Zepto 外掛模塊非常簡單。在分析核心模塊邏輯時(shí),可以通過此方法改寫函數(shù),或者嘗試基于業(yè)務(wù)需求配置一個(gè)新的數(shù)據(jù)結(jié)構(gòu),再利用 Zepto 實(shí)現(xiàn)對(duì) DOM 的增刪改查。

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

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

相關(guān)文章

  • Zepto源碼之Selector模塊

    摘要:如果偽類的參數(shù)不可以用轉(zhuǎn)換,則參數(shù)為字符串,用正則將字符串前后的或去掉,再賦值給最后執(zhí)行回調(diào),將解釋出來的參數(shù)傳入回調(diào)函數(shù)中,將執(zhí)行結(jié)果返回。重寫的方法,改過的調(diào)用的是方法,在回調(diào)函數(shù)中處理大部分邏輯。 Selector 模塊是對(duì) Zepto 選擇器的擴(kuò)展,使得 Zepto 選擇器也可以支持部分 CSS3 選擇器和 eq 等 Zepto 定義的選擇器。 在閱讀本篇文章之前,最好先閱讀《...

    Jioby 評(píng)論0 收藏0
  • Zepto 源碼之集合元素查找

    摘要:方法是將集合中不符合條件的元素查找出來。判斷集合中的第一個(gè)元素是否匹配指定的選擇器。這個(gè)在讀源碼之集合操作有講過,如果集合個(gè)數(shù)大于零,則表示滿足條件。返回集合中所有元素指定的屬性值。獲取集合中每個(gè)元素的前一個(gè)兄弟節(jié)點(diǎn)。 這篇依然是跟 dom 相關(guān)的方法,側(cè)重點(diǎn)是跟集合元素查找相關(guān)的方法。 讀Zepto源碼系列文章已經(jīng)放到了github上,歡迎star: reading-zepto 源碼...

    DC_er 評(píng)論0 收藏0
  • Zepto源碼分析(一)核心代碼分析

    摘要:源碼分析一核心代碼分析源碼分析二奇淫技巧總結(jié)本文只分析核心的部分代碼,并且在這部分代碼有刪減,但是不影響代碼的正常運(yùn)行。當(dāng)長度為則不添加內(nèi)容,否則逐個(gè)將逐個(gè)到當(dāng)前實(shí)例新增直接返回一個(gè)新的構(gòu)造函數(shù)添加初始化方法。 Zepto源碼分析(一)核心代碼分析Zepto源碼分析(二)奇淫技巧總結(jié) 本文只分析核心的部分代碼,并且在這部分代碼有刪減,但是不影響代碼的正常運(yùn)行。 目錄 * 用閉包封裝Z...

    BicycleWarrior 評(píng)論0 收藏0
  • Zepto 源碼分析 1 - 進(jìn)入 Zepto

    摘要:選擇的理由是一個(gè)用于現(xiàn)代瀏覽器的與大體兼容的庫。環(huán)境搭建分析環(huán)境的搭建僅需要一個(gè)常規(guī)頁面和原始代碼一個(gè)常規(guī)頁面打開的首頁即可,在開發(fā)人員工具中即可使用原始代碼本篇分析的代碼參照,進(jìn)入該代碼分支中即可。 選擇 Zepto 的理由 Zepto is a minimalist JavaScript library for modern browsers with a largely jQue...

    Aklman 評(píng)論0 收藏0
  • Zepto 源碼之神奇的 $

    摘要:返回值為,如果能查找到元素,則將元素以數(shù)組的形式返回,否則返回空數(shù)組排除不合法的。的第一個(gè)字符為,并且為標(biāo)簽。如果存在,則查找下選擇器為的所有子元素。正則表達(dá)式為如果沒有指定標(biāo)簽名,則獲取標(biāo)簽名。包裹元素的即為所需要獲取的。 經(jīng)過前面三章的鋪墊,這篇終于寫到了戲肉。在用 zepto 時(shí),肯定離不開這個(gè)神奇的 $ 符號(hào),這篇文章將會(huì)看看 zepto 是如何實(shí)現(xiàn) $ 的。 讀Zepto源碼...

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

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

0條評(píng)論

ctriptech

|高級(jí)講師

TA的文章

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