jQuery 源码剖析 - 2.选择器
一.准备工作
- 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
数据是属于什么类型?不同的数据类型,分析不同数据类型的行为,有以下几种情况:
- 如果传过来的数据是字符串:那么要分析字符串是否是HTML标签,如果是HTML那么就通过正则提取关键字并创建一个HTM标签输出
- 如果传过来的数据是不是html元素,那么要通过 querySelectorAll 来查询过滤,如果可以查询到是DOM中的选择器,那么就遍历输出他的值。
- 如果传过来的元素是DOM节点,直接返回
- 如果传过来的数据是一个对象方法,那么要通过
$(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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论