天天看點

2.實作jQuery選擇器功能描述

功能描述

用過jquery的同學都知道,在$()函數中可以傳遞多種參數來生成jquery對象,本次就探究一下如何實作此功能.

$()函數中主要接受的參數有以下三種:字元串類型,dom對象和函數.

//1.傳入字元串類型選擇器 
$("#container")

//2.傳入字元串類型html代碼
$("<div>123</div>")

//3.傳入dom類型
$(document.getElementById("#xxx"))

//4.傳入函數類型
$(document).ready(function(){
  console.log("dom加載完畢!");
})
   
           

源碼實作和解析

在上一章中我們已經學習了如何建立一個jquery對象,将其部分代碼拷貝過來.在init函數中我們首先要對使用者傳入的兩個參數content和context解析.context是上下文對象,如果使用者省略不傳預設為document.而content按照上面的參數類型描述主要分為字元串,函數和dom對象三種類型.

當content為字元串類型它可能有兩種情況,一種是類似"<div>123<div>"的html代碼,我們通過判端該字元串是否有左右<>的閉合辨別符來判斷該參數是否是一段html代碼,如果是的話我們就要把這段html生成dom節點.另一種字元串類型是選擇器,利用context.querySelectorAll()此API去尋找選擇器擷取dom節點.經過上述步驟的目的就是為了擷取到使用者想要的比對的原生dom對象,接下來的工作便是如何将原生dom對象轉化成jquery對象,實作此功能主要通過merge函數.

merge函數首先判端第一個參數是否是普通數組,如果是普通數組直接利用concat合并就可以了,否則的話第一個參數我們就把它設定為類數組對象(jquery就是一個類數組對象).通過周遊第二個數組将其元素全部加到類數組對象上并最後更新size屬性傳回此類數組對象,此類數組對象便是最終我們想要的jquery對象.

當content為函數類型時,我們隻需要将函數收集起來放到fun_list數組中,并且監聽浏覽器的DOMContentLoaded事件,當浏覽器中的dom元素全部加載完畢後我們循環執行fun_list數組中的函數即可.

實作源碼如下:

(function(global){

  var $,jQuery;

  $ = jQuery = function(content,context){
      return new jQuery.fn.init(content,context);
  }
  
  //收集函數
  const fun_list = [];

  jQuery.fn = jQuery.prototype = {
      init:function(content,context){
        context = context || document;
        this.context = context;
        if(typeof content === "string"){
            let child_nodes = [];
            if(content.startsWith("<") && content.endsWith(">") && content.length>2){ //建立dom節點
                const DIV = context.createElement("DIV");
                DIV.innerHTML = content;
                child_nodes = DIV.children;
            }else{ //尋找dom節點
                child_nodes = context.querySelectorAll(content);
            }
            jQuery.fn.merge(this,child_nodes);
            return this;
        }else if(content.nodeType){ //判斷context是不是node節點
            jQuery.fn.merge(this,[content]);
            return this;
        }else if(typeof content === "function"){//判端context是不是函數
            fun_list.push(content);
        }
      },
      merge:function(array1,array2){
        if(array1 instanceof Array){
            return array1.concat(array2);
        }else{
            const length = array1.length || 0;
            i = length;
            for(j=0;j<array2.length;j++){
                array1[i+j] = array2[j];
            }
            array1.length = length+array2.length;
            return array1;
        }  
      },
      ready:function(fun){
        fun_list.push(fun);
      } 
  }

  jQuery.fn.init.prototype = jQuery.fn;

  global.$ = global.jQuery = $;
  
  function domLoadComplete(){
    document.addEventListener('DOMContentLoaded', function () {
        document.removeEventListener('DOMContentLoaded', arguments.callee, false);            
        fun_list.forEach(function(fn){
            fn();
        })
      }, false);
  }
  domLoadComplete();
}
)(window)
           

結果驗證

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./lib/jquery_like.2.js"></script>
</head>
<body>
    
    <div id="container" class="a">123</div>
    <div class="a">456</div>
    <div class="a">789</div>

</body>
<script>
    console.log($("#container"));
    console.log($(".a"));
    $(document).ready(function(){
        console.log("dom加載完畢!");
    })
    $(function(){
        console.log("可以重複添加函數!");
    })
</script>
</html>
           
2.實作jQuery選擇器功能描述