jQuery 源码剖析 - 2.选择器

发布于 2023-01-27 21:57:46 字数 5491 浏览 65 评论 0

一.准备工作

  • 1.首先官网下载源码 jQuery 官网
  • 2.选择 jQuery 版本并下载到本地,并在本地给自己新建件 myjQuery-1.0.1.js(这个文件是用来仿写 jQuery)。
  • 3.创建入口文件并引入这官方 jQuery 和自己创建的 myjQuery-1.0.1.js 文件。
  • 4.开始剖析源码。

二.开始剖析

本次主要剖析 jQuery 选择器的封装,在平时使用 jQuery 时,非常容易的通过 $() 就可以查找相关的选择器,那么具体是如何实现的呢?跟随我来一探究竟,首先先来做个例子,我们先通过官方的 jQuery 框架输出以下几个实例:

// 传入字符串
console.log($("a"));  //创建DOM节点包装成jQuery对象
// 传入HTML
console.log($("<div>"));  // //创建DOM节点包装成jQuery对象
// 传入对象
console.log($(document));
// 传入选择器
console.log($('.box'));
// 传入对象
console.log($(this));   // 把传入的对象包装成jQuery对象 
// 传入方法 
$(function(){
  console.log(11111);  //这个是在页面加载完成后加载执行的,等效于在DOM文档加载完成后执行了$(document).read()方法    
})

输出结果:

根据输入的结果我们类阅读源码,反推如何实现类似的效果,首先 $() 调用的是 jQuery.prototype.init() 的初始化方法,所以要在 init() 方法里做扩展。

init:function (selector,context) {
  context = context || document;
  var match,elem,index=0;
  if(!selector){
    return this;
  }
  /**
   * 检测传过来的数据是否是字符串
   * **/
  if(typeof selector === "string"){
    if (selector.charAt(0) === "<" && selector.charAt(selector.length-1)=== ">" && selector.length>=3) {
       // 此时是HTML  
      match = [selector];
    }
    // match 有值的情况
    if (match) {
      /**
       * 合并数组
       * merge parseHTML是静态扩展方法
       * **/
      jQuery.merge(this, jQuery.parseHTML(selector,context));
      // 查询DOM节点  
    } else {
      elem = document.querySelectorAll(selector);
      // 转化为真数组
      var elems = Array.prototype.slice.call(elem);
      this.length = elem.length;

      for (;index = elem.length;index ++) {
        this[index] = elems[index];
      }
      this.context = context;
      this.selector = selector;
    }
    // HANDLE: $(DOMElement)
  } else if (selector.nodeType){ // 
    this.context = this[0] = selector;
    this.length = 1;
    return this;
    //  $(function)
    // 函数处理
  } else if (isFunction( selector )) { 
    jQuery(document).ready(selector); // 实例对象的方法
  }
  /**
  *makeArray 是jQuery扩展的方法
  **/
  return jQuery.makeArray( selector, this );
},

jQuery 扩展的静态方法

    /**
   *  合并数组
   *  [first] jQuery的实例对象  this
   *  [second] DOM 节点 
   */
  merge:function (first,second) {
    var l = second.length, // 1
      i = first.length, // 0
      j = 0;
    if (typeof l === "number") {
      for ( ; j < l; j++){ // 遍历DOM节点
        first[i++] = second[j];
      }
    } else {
      while (second[j] !== undefined) {
        first[i++] = second[j++];
      }
    } 
    first.length = i;
    // 返回jQuery的实例对象
    return first;   
  },
  /**
   * 解析HTML
   * [data] 传入的数据
   * [context] 返回的值
   * **/
  parseHTML:function (data,context) {
    if (!data || typeof data !== "string") {
      return null;
    }
    /**
     * exec() 是正则方法 返回为数组   
     * [0] 为正则表达式相匹配的文本
     * [1] 表达式相匹配的文本  
     * **/
    // 过滤掉符号,只提取标签 "<a>" ==> "a"
    var parse = rejectExp.exec(data);
    // 返回一个创建DOM的元素
    return [context.createElement(parse[1])];
  },
  /**
   * 将一个类数组对象转换为真正的数组对象
   * [arr] 传入的数组
   * [result] 返回的数组
   * **/
  makeArray:function(arr,result){
    var ret = result || [];
    if ( arr != null ) {
      if ( isArrayLike( Object( arr ) ) ) {
        jQuery.merge( ret,
          typeof arr === "string" ?
          [ arr ] : arr
        );
      } else {
         [].push.call( ret, arr );
      }
    }
    return ret;
  },
  isReady:false,
  readylist:[],// list 
  ready:function(){ // 事件函数
     jQuery.isReady = true;
     jQuery.readylist.forEach(function(callback){
       callback.call(document);
     })  
     // 清空
     jQuery.readylist = null;
  }
});
  /**
 *  定义全局函数
 * **/

// 判断是否是方法
var isFunction = function isFunction( obj ) {   
  return typeof obj === "function" && typeof obj.nodeType !== "number";
  };
// 判断是否是windows
var isWindow = function isWindow( obj ) {
  
return obj != null && obj === obj.window;
};

通过以上代码可以做以下几点分析:

1、 $() 传过来的 selector 数据是属于什么类型?不同的数据类型,分析不同数据类型的行为,有以下几种情况:

  1. 如果传过来的数据是字符串:那么要分析字符串是否是HTML标签,如果是HTML那么就通过正则提取关键字并创建一个HTM标签输出
  2. 如果传过来的数据是不是html元素,那么要通过 querySelectorAll 来查询过滤,如果可以查询到是DOM中的选择器,那么就遍历输出他的值。
  3. 如果传过来的元素是DOM节点,直接返回
  4. 如果传过来的数据是一个对象方法,那么要通过 $(document).read() 方法,监听拦截 DOMContentLoaded 方法,改变对象方法的指针然后依次加入到数组中,输出。

通过剖析 jQuery 选择器模块,进行测试:

// 创建 DOM
// 传入字符串
console.log($("a"));  //创建DOM节点包装成jQuery对象
// 传入HTML
console.log($("<div>"));  // //创建DOM节点包装成jQuery对象
// 传入对象
console.log($(document));
// 传入选择器
console.log($('.box'));
// 传入对象
console.log($(this));   // 把传入的对象包装成jQuery对象
$(function(){
  console.log(11111); 

输出结果:

源码下载:https://www.wenjiangs.com/wp-content/uploads/2023/01/ZHSGjwwCkmcHlvJ9.zip

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
22 人气
更多

推荐作者

lorenzathorton8

文章 0 评论 0

Zero

文章 0 评论 0

萧瑟寒风

文章 0 评论 0

mylayout

文章 0 评论 0

tkewei

文章 0 评论 0

17818769742

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文