jQuery(三)之 选择器(基础版)
对于jquery的调用,我们一般都会传入参数
html: <div></div> js: console.log($('<a />')); console.log($('div'));
一、前置(dom对象和jquery对象)
- dom对象,
关于这个,应该是前端的基础知识了,在文档对象模型中,每个部分都是节点。 - jquery对象
这个是指通过jquery构造函数创建出来的对象,可以通过jquery选择器获取到,并以类数组的形式保存在jquery中
二、实践
仔细观察返回的jquery对象,感觉像是对dom节点进行封装,并将其保存在jquery上
一、实现一个基本的创建选择器
- 获取到传入参数,判断是创建一个jquery节点,还是查询节点,
- 创建新节点,传入的是一个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对象。 } } } }
- 确定好是需要创建一个节点之后,我们就需要思考需要进行什么操作。需要将标签名解析出来,然后利用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] } }
好了,现在我们就可以看下代码的执行结果了。
ok,勉强可以实现,但好像还是有点不对的样子, 让我们来看下jquery的源码。
可以看出是调用了merge方法。跳转到merge方法查看一下,一般来说,merge用于合并两个数组, 也可以用于将数组合并在有length属性的对象上。// 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; }
了解的区别后,我们来优化代码吧, 优化
二、实现一个基本的标签选择器
- dom原生节点查询
- document.queryselector
- document.queryselectorall //返回一个nodelist
- 实践
利用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; }
三、关于传入一个方法的选择器
- 首先看下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。
- 在看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); }
- 可以看下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是什么,我们在代码中找一下看下,
var readylist = jquery.deferred(); jquery.fn.ready = function(fn) { ready.then(fn).catch(error) { jquery.readyexception(error); } return this; }
从以上代码可以看出,readylist是deferred函数的返回值,且从下面的调用,可以推测defferred函数应该是个promise对象。对于defferred函数,下次再仔细研究一下。
现在让我们来回顾整个函数流程:
上面的内容只是我自己的理解,如果有什么不对的地方,希望大家帮忙指出啊!
上一篇: 利用MySQL系统数据库做性能负载诊断
下一篇: 微信公众号之获取openId