jQuery 源码分析和使用心得 - 文档遍历 ( traversing.js )
2014-11-24 14:22
597 查看
jQuery之所以这么好用, 首先一点就是$()方法和它强大的选择器. 其中选择器使用的是sizzle引擎, sizzle是jQuery的子项目, 提供高效的选择器查询. 有个好消息告诉大家, 就是sizzle可以独立使用, 如果你觉得jQuery太大但又非常喜欢它的选择器, 那不妨可以用sizzle. 感兴趣的话可以到官方网站了解.
本系列内部不准备解析sizzle的源码, 一是sizzle内容相对独立, 二是内容主要涉及算法, 与整体的代码设计关系不大, 三嘛, 我的实力有限, 遇到算法就退缩了,哈哈! ( q君: 这才是主要原因吧! ). 不过也许以后技术水平到了, 出一个sizzle解析专题也未可知啊!
回过神来, 看我们的标题就知道了, jQuery这么强大, 它的众多方便的遍历方法也是一大功臣啊 .
jQuery提供了十几种方便的链式遍历方法, 让我们可以在繁杂的dom结构中自由游走, 这一章里我们就来一探究竟, 看看里面到底蕴含了怎么样奇妙的实现原理呢!
基本遍历: dir sibling
dir有三个参数, function( elem, dir, until ), elem是dom对象, dir是需要遍历的属性, until是截至条件. 运行过程是循环查找elem的dir的属性, 直到没有后续元素 或者找到了document根节点(elem.nodeType !== 9) , 将所有查找到的元素放到数组中返回 .
sibling有两个参数, function( n, elem ) , n是起始dom对象, elem是结束dom对象. 它通过不断寻找nextSibling, 直到找到非element的对象(n.nodeType === 1) 或者找到了elem为止, 将所有查找到的元素放到数组中返回 .
另外还有一个基本遍历方法sibling, 这个方法并没有对外公开. 它查找dir属性直到遇到第一个element的对象或者没找到, 并返回这个对象.
当我第一次看见这段代码的时候, 不禁感叹js真是太灵活了, 而jQuery的开发者将这种灵活性发挥的淋漓尽致. 整段代码前半部分看起来就像是一个配置. 函数名, 后面是方法的实现. 比如parents, 他调用dir方法, 传入当前elem和遍历属性"parentNode", 这个方法就会不断访问元素的parentNode属性查找父级元素, 一直查到 document位置, 返回的就是当前元素的所有父级元素.
再看后半部分, jQuery.map( this, fn, until ) 遍历本身, 对每一个元素执行fn方法, 传入until参数. 返回的就是所有遍历后得到的元素(dom元素, 可能会有重复). jQuery.filter( selector, matched )对元素进行过滤, 然后去重, 如果是parent, prev等方法, 就将结果反转顺序, 最后压栈返回.
2. 先提供基本方法, 然后创建快捷方式的做法可以在以后的代码中借鉴
3. 感叹jQuery吧!
本系列内部不准备解析sizzle的源码, 一是sizzle内容相对独立, 二是内容主要涉及算法, 与整体的代码设计关系不大, 三嘛, 我的实力有限, 遇到算法就退缩了,哈哈! ( q君: 这才是主要原因吧! ). 不过也许以后技术水平到了, 出一个sizzle解析专题也未可知啊!
回过神来, 看我们的标题就知道了, jQuery这么强大, 它的众多方便的遍历方法也是一大功臣啊 .
jQuery提供了十几种方便的链式遍历方法, 让我们可以在繁杂的dom结构中自由游走, 这一章里我们就来一探究竟, 看看里面到底蕴含了怎么样奇妙的实现原理呢!
预热
DOM树
要说遍历, 首先要介绍"树" ,一些没有看过数据结构或者不了解html dom结构的人可能对树没有什么概念, 如果你已经知道了, 就跳过本段吧. 我简单的说明一下, 具体定义和非常正规的说明我就不说了,相信度娘一定可以满足你的. 我们先来想象一下一颗树, 他有根, 然后分叉出大的枝干, 然后就分出小树枝 ... 最后到叶子结束. 如果我们把根, 枝干, 小树枝, 叶子 抽象成节点, 他们之间存在连接, 这些节点和连接就组成了树. 应用到html中就是如下(来自百度图片搜索)dir: function( elem, dir, until ) { var matched = [], truncate = until !== undefined; while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate && jQuery( elem ).is( until ) ) { break; } matched.push( elem ); } } return matched; }, sibling: function( n, elem ) { var matched = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { matched.push( n ); } } return matched; }
基本遍历: dir sibling
dir有三个参数, function( elem, dir, until ), elem是dom对象, dir是需要遍历的属性, until是截至条件. 运行过程是循环查找elem的dir的属性, 直到没有后续元素 或者找到了document根节点(elem.nodeType !== 9) , 将所有查找到的元素放到数组中返回 .
sibling有两个参数, function( n, elem ) , n是起始dom对象, elem是结束dom对象. 它通过不断寻找nextSibling, 直到找到非element的对象(n.nodeType === 1) 或者找到了elem为止, 将所有查找到的元素放到数组中返回 .
另外还有一个基本遍历方法sibling, 这个方法并没有对外公开. 它查找dir属性直到遇到第一个element的对象或者没找到, 并返回这个对象.
function sibling( cur, dir ) { while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {} return cur; }
快捷方式
jQuery提供 parent , parents , next 等十几种遍历方法, 这些方法都是以三个基本遍历方法为基础实现, 这段代码看起来非常优雅, 我忍不住要再贴一遍, 虽然上面已经有了.jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return elem.contentDocument || jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var matched = jQuery.map( this, fn, until ); if ( name.slice( -5 ) !== "Until" ) { selector = until; } if ( selector && typeof selector === "string" ) { matched = jQuery.filter( selector, matched ); } if ( this.length > 1 ) { // Remove duplicates if ( !guaranteedUnique[ name ] ) { jQuery.unique( matched ); } // Reverse order for parents* and prev-derivatives if ( rparentsprev.test( name ) ) { matched.reverse(); } } return this.pushStack( matched ); }; });
当我第一次看见这段代码的时候, 不禁感叹js真是太灵活了, 而jQuery的开发者将这种灵活性发挥的淋漓尽致. 整段代码前半部分看起来就像是一个配置. 函数名, 后面是方法的实现. 比如parents, 他调用dir方法, 传入当前elem和遍历属性"parentNode", 这个方法就会不断访问元素的parentNode属性查找父级元素, 一直查到 document位置, 返回的就是当前元素的所有父级元素.
再看后半部分, jQuery.map( this, fn, until ) 遍历本身, 对每一个元素执行fn方法, 传入until参数. 返回的就是所有遍历后得到的元素(dom元素, 可能会有重复). jQuery.filter( selector, matched )对元素进行过滤, 然后去重, 如果是parent, prev等方法, 就将结果反转顺序, 最后压栈返回.
使用建议
1. 通过prevObject可以获取上一次查找结果2. 先提供基本方法, 然后创建快捷方式的做法可以在以后的代码中借鉴
3. 感叹jQuery吧!
相关文章推荐
- jQuery 源码分析和使用心得 - core.js
- jQuery源码分析-11 DOM遍历-Traversing-3个核心函数
- [原创] jQuery源码分析-11 DOM遍历-Traversing-3个核心函数
- jQuery 源码分析和使用心得 - 关于源码
- jQuery源码分析-11 DOM遍历-Traversing-DOM遍历方法
- jQuery 源码分析和使用心得 - 序
- [原创] jQuery源码分析-11 DOM遍历-Traversing-DOM遍历方法
- jquery.pagination.js源码分析,曾输入框跳转
- jquery.simpleTree.js使用心得
- jQuery 中插件的使用与开发---附全部源码(含 jQuery1.3.2 for VS 的智能提示js文件)
- SlidesJS基本使用方法和官方文档解释 【Jquery幻灯片插件 Jquery相册插件】
- ddpowerzoomer.js利用jQuery扩展,实现对图片局部放大功能(源码分析)
- 18、使用jQuery操作DOM之遍历文档树
- 43、实例 使用jQuery遍历文档树
- [JS]JQuery源码分析
- 使用jQuery对js对象和数组的遍历以及序列化
- jquery.cookie.js源码和使用方法
- 【js与jquery】jquery的一个通用的专门用于遍历的全局方法$.each()的使用
- jQuery核心源码core.js分析
- jQuery核心源码core.js分析