jQuery是一个非常好用的开源javascript框架,因为其语法简洁通用,尤其是选择器和css选择器非常相似,非常适合于前段开发人员使用,并且jquery还有很多成熟的插件可供使用。我在这篇博客里不讲jquery的应用,因为这样的文章在网上有很多,而且很多人只要jquery api文档一看就知道该怎么使用了。
熟悉css的前段开发人员一看jquery的选择器就非常清楚了,因为jquery的dom元素选择器表达式和css选择器表达式非常的相似。下面我就来说说,jquery是怎样实现这种表达式的。jquery的所有函数实际上是一个匿名函数的内部函数。jquery通过javascript的闭包机制来保护内部函数,防止外部程序随意调用内部函数。这个匿名函数是(function(){}),在这个匿名函数后面加个(),就能调用了这个匿名函数。
设置jquery变量,使这个变量为window对象,使其 jQuery = window.jQuery = window.$ = function( selector, context ) {
return new jQuery.fn.init( selector, context );
} jQuery.fn为jQuery的原生对象,jQuery.fn是一个json格式的object对象,其中有个函数init,这个函数的执行流程如下:首先判断selector有没有定义,如果没有定义,selector变为document对象;如果selector不是dom元素,那么执行下面的流程,如果selector为dom元素,将该selector赋为jquery的第一个数组元素,将jquery的长度设为1,将selector赋给context对象,并返回该jquery对象。如果selector为string对象,正则表达式去匹配该对象,这个正则表达式匹配html元素或者id元素。如果为html元素,则创建一个xml dom元素。如果为id元素,则通过document.getElementById获取element节点。如果为其他的类似css选择器表达式,很多浏览器支持document.querySelector和document.querySelectorAll方法,这种方法传入的参数都是css选择器表达式,前者返回的对象是node对象,后者返回的是nodelist对象。将得到的nodelist对象转换为数组,并将其放入jquery对象中,返回该jQuery对象。
如果浏览器不支持这种方法(譬如ie6),jquery还提供了对jquery表达式的解析。如果传入的参数为*,同时传过来的context为查找范围,默认的是document。首先和几个正则表达式进行匹配,这些正则表达式是Expr.match里边,分别为ID CLASS NAME ATTR TAG CHILD POS PSEUDO,当然*肯定匹配TAG类型的正则表达式。直接调用context.getElementsByTagName("*")得到所有的对象,再将这些对象放入jquery中,进行一下封装就变成了jquery对象。
如果传过来的参数为class名字,同时传过来的context为查找范围,默认的是document。首先和几个正则表达式进行匹配,这些正则表达式是Expr.match里边,分别为ID CLASS NAME ATTR TAG CHILD POS PSEUDO,当然class肯定匹配CLASS类型的正则表达式。直接调用context.getElementsByClassName得到所有的对象,再将这些对象放入jquery中,进行一下封装就变成了jquery对象。
如果传过来的参数为name节点名称,同时传过来的context为查找范围,默认的是document。首先和几个正则表达式进行匹配,这些正则表达式是Expr.match里边,分别为ID CLASS NAME ATTR TAG CHILD POS PSEUDO,当然name肯定匹配CLASS类型的正则表达式。直接调用context.getElementsByTagName得到所有的对象,再将这些对象放入jquery中,进行一下封装就变成了jquery对象。
如果传过来的参数为多个选择器表达式,则对这些表达式采用递归的方法进行逐个解析,方法和上面的相同,只不过将最后得到的对象统一封装为jquery对象。
如果传过来的参数为匹配所有后代元素的层级表达式,则先对后代元素表达式进行解析,得到所有匹配后代元素的对象。然后得到这些后代元素的parentNode对象进行循环查找(即查找这些元素的parent对象的parent对象),和父元素进行比较,如果匹配,则将这些匹配的后代元素集合封装为jquery对象。如果传过来的参数为匹配所有子元素的层级表达式,则先对子元素表达式进行解析,得到所有匹配子元素的对象。然后得到这些子元素的parentNode对象进行查找,而不对其parent对象的parent对象进行查找,和父元素进行比较,如果匹配,则将这些匹配的子元素集合封装为jquery对象。
如果传过来的参数为匹配相邻元素的层级表达式,则先对next元素表达式进行解析,得到所有匹配next元素的对象。然后得到这些next元素的previousSibling对象,和prev元素进行比较,如果匹配,则将这些匹配的next元素集合封装为jquery对象。如果传过来的参数为匹配所有相邻元素的层级表达式,则先对next元素表达式进行解析,得到所有匹配next元素的对象。然后循环查找得到这些next元素的所有previousSibling对象,和prev元素进行比较,如果匹配,则将这些匹配的next元素集合封装为jquery对象。
如果传过来的参数为匹配基本选择器的表达式,在Expr这个JSON对象中,有个setFilters的object对象,首先正则表达式进行匹配,将:之前的表达式进行解析,得到所有对应的dom元素,再对:之后的表达式进行匹配,与Expr中的setFilters对象中的函数进行比较,如果匹配,则将匹配的dom元素放入jquery对象中,封装为一个jquery对象。
如果传过来的参数为内容选择器的表达式,在Expr这个JSON对象中,有个filters的object对象,首先正则表达式进行匹配,将:之前的表达式进行解析,得到所有对应的dom元素,再对:之后的表达式进行匹配,在之前匹配的dom元素范围内查找,与Expr中的filters对象中的函数进行比较,如果匹配,则将匹配的dom元素放入jquery对象中,封装为一个jquery对象。其他的和这个很类似。
如果传过来的参数为属性选择器的表达式,在Expr这个JSON对象中,有个filter的object对象,有个ATTR的函数。首先正则表达式进行匹配,得到标签表达式和属性表达式。将标签表达式进行解析,得到所有对应的dom元素,再属性表达式进行解析,通过element.getAttribute函数在之前匹配的dom元素范围内查找,根据属性的符号,查找出相匹配的对象,将匹配的dom元素放入jquery对象中,封装为一个jquery对象。
如果传过来的参数为表单对象属性选择器的表达式,在Expr这个JSON对象中,有个filters的object对象,首先正则表达式进行匹配,将:之前的表达式进行解析,得到所有对应的dom元素,再对:之后的表达式进行匹配,在之前匹配的dom元素范围内查找,与Expr中的filters对象中的函数进行比较,如果匹配,则将匹配的dom元素放入jquery对象中,封装为一个jquery对象。
jquery选择器的查找方式,具体的细节我写得不是特别详细,如果太详细了,一篇博客是绝对写不完的。下期我为大家介绍jquery的筛选机制处理方式和插件机制。这两个是jquery当中最复杂的两个,其余都很简单了。