功能描述
用過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>