天天看点

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选择器功能描述