jQuery(三)之 選擇器(基礎版)

對於jQuery的調用,咱們通常都會傳入參數html

html: <div></div>
  js: console.log($('<a />'));
    console.log($('div'));

Image text

1、前置(DOM對象和jQuery對象)

  1. DOM對象,
    關於這個,應該是前端的基礎知識了,在文檔對象模型中,每一個部分都是節點。
  2. jQuery對象
    這個是指經過jQuery構造函數建立出來的對象,能夠經過jQuery選擇器獲取到,並以類數組的形式保存在jQuery中

2、實踐

仔細觀察返回的jQuery對象,感受像是對DOM節點進行封裝,並將其保存在jQuery上前端

1、實現一個基本的建立選擇器
  1. 獲取到傳入參數,判斷是建立一個jquery節點,仍是查詢節點,
  2. 建立新節點,傳入的是一個html標籤,以此進行判斷
//獲取到傳入的參數
     var jQuery = function(selector, content) {
       return new jQuery.prototype.init(selector, content);
     }
     jQuery.prototype = {
         length: 0,
         init: function(selector, content) {
           content = content || document;
           var match; //match 用來保存selector;
           if(typeof selector === 'string') {
             // 判斷selector傳入的是一個html標籤;
             if(selector.charAt(0) === '<' && selector.charAt(selector.length-1) === '>' && selector.length >= 3 ) {
               match = [selector];
             }
             if (match) {
               //建立一個jQuery對象。
             }
           }
         }
       }
  1. 肯定好是須要建立一個節點以後,咱們就須要思考須要進行什麼操做。須要將標籤名解析出來,而後利用createElement建立節點,並保存。
    • 定義一個html解析函數
    var reg = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
    jQuery.extend({
         parseHtml: function(data, content) {
           if (!data && typeof data != 'string') {
             return null;
           }
           var parse = reg.exec(data);
           return [content.createElement(parse[1])] //ok,這裏是將建立的一整個DOM節點保存在了數組中。
         }
    })
    • 已經能夠獲取到建立的節點了,下面將節點掛載在jQuery上就能夠了。
    if(match) {
         for(; i < match.length; i++) {
           var opt = match[i]
           this[i]=jQuery.parseHtml(opt, content)[i]
         }
    }

    好了,如今咱們就能夠看下代碼的執行結果了。
    image text
    ok,勉強能夠實現,但好像仍是有點不對的樣子, 讓咱們來看下jQuery的源碼。
    image text
    能夠看出是調用了merge方法。跳轉到merge方法查看一下,通常來講,merge用於合併兩個數組, 也能夠用於將數組合並在有length屬性的對象上。jquery

    // push.apply(_, arraylike) throws on ancient WebKit
    
    merge: function (first, second) {
        var len = +second.length,
          j = 0,
          i = first.length;
        for (; j < len; j++) {
          first[i++] = second[j];
        }
        first.length = i;   
        return first;
    }
    瞭解的區別後,咱們來優化代碼吧,
  2. 優化數組

2、實現一個基本的標籤選擇器
  1. DOM原生節點查詢
    • document.querySelector
    • document.querySelectorAll //返回一個NodeList
  2. 實踐
    利用document原生查取節點的方式,得到結果,再將其每個放在jQuery上
var ele, i = 0;
     if(match) {}
     else {
         ele = document.querySelectorALL(selector);
         for(; i < ele.length; i++) {
           this[i] = ele[i]
         }
         this.length = ele.length;
     }
3、關於傳入一個方法的選擇器
  1. 首先看下init中是如何處理的:
var rootjQuery;
  init = jQuery.fn.init = function(selector, context, root) {
    ...
    root = root || rootjQuery;
    if(typeof selector === 'string') {
      ...
    } else if (isFunction(selector)) {
      return root.ready !== undefined ? root.ready(selector) : selector(jQuery);
    }
  }
  rootjQuery = jQuery(document);

代碼能夠看出,其實js是能夠傳遞三個參數的,且root默認爲document,若是root.ready沒有初始話的話就馬上執行傳入的方法,不然調用root.ready方法。關於root,從代碼能夠看出,是個全局,那麼root.ready == jQuery.ready。promise

  1. 在看ready方法前,須要明確一個問題,jquery傳入方法的處理是在文檔加載以後執行,因此首先應該對文檔是否加載完畢進行判斷。
function completed() {
      document.removeEventListener('DOMContentLoaded',completed);
      window.removeEventListener('load', completed);
      jQuery.ready();
    }
    
    if(document.readyState === 'complete' || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
      window.setTimeout(jQuery.ready);
    } else {
      //dom加載完畢後,調用complate移除監聽事件。
      document.addEventListener('DOMContentLoaded', complete);
      window.addEventListener('load', completed);
    }
  1. 能夠看下jQuery.ready方法了。
jQuery.extend({
    // DOM是否已經準備好要使用了,發生更改,則修改成true;
    isReady: false,
    //跟蹤就緒事件觸發前要等待的項目數計數器
    readyWait: 1,
    ready: function(wait) {
      if(wait === true ? --jQuery.readyWait : jQuery.isReady) {
        return ;
      }
      //DOM節點已經準備好了
      jQuery.isReady = true;
      
      if(wait !== true && --jQuery.readyWait > 0) {
        return 
      }
      //若是有函數綁定,當即執行。
      readyList.resolveWidth(document, [jQuery])
    }
  })

從2.的時候能夠看出,在DOM節點加載完的時候,調用了一次ready,此時沒有傳入wait,ready中第一個判斷直接跳過,記錄jQuery.isReady = true,而後再看下一句執行,調用readyList.resolveWidth方法,此時DOM節點已經加載完畢,能夠執行綁定的函數了,
關於這個readyList是什麼,咱們在代碼中找一下看下,app

var readyList = jQuery.Deferred();

   jQuery.fn.ready = function(fn) {
     ready.then(fn).catch(error) {
       jQuery.readyException(error);
     }
     return this;
   }

從以上代碼能夠看出,readyList是Deferred函數的返回值,且從下面的調用,能夠推測Defferred函數應該是個promise對象。對於Defferred函數,下次再仔細研究一下。
如今讓咱們來回顧整個函數流程:
Image text
上面的內容只是我本身的理解,若是有什麼不對的地方,但願你們幫忙指出啊!dom

相關文章
相關標籤/搜索