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

相关文章
相关标签/搜索