- 在jQuery.fn.init函数中,最终的结果是把Dom元素放到jQuery对象的集合,我们可以传入单个Dom元素或Dom元素集合直接把其存到jQuery对象的集合。但是如果第一个参数是string类型的话,如#id就要把Dom文档树去查找。对于html的片断就得生成Dom元素。我们再进一步,传入的单个Dom元素或Dom元素集合参数又是从那里来的?我们可以通过Dom元素的直接或间接的查找元素的方式。
- 这一部分首先分析如何从html的片断就得生成Dom元素,然后分析jQuery是如何通过直接或间接的方式在在Dom树中找到dom元素,第三就是分析基于CSS1~CSS3的CSS selector。
-
- 3.1生成Dom元素
- Init方法中通过jQuery.clean([match[1]], context);来实现把html片断转换成Dom元素,这是一个静态方法:
-
- clean : function(elems, context) {
- var ret = [];
- context = context || document;
-
- if (typeof context.createElement == 'undefined')
-
- context = context.ownerDocument || context[0]
- && context[0].ownerDocument || document;
-
- jQuery.each(elems, function(i, elem) {
-
- if (typeof elem == 'number')elem += '';
- if (!elem) return;
- if (typeof elem == "string") {
-
-
-
- elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag) { return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)? all: front + "></" + tag+ ">";} );
-
- var tags = jQuery.trim(elem).toLowerCase(),
- div = context.createElement("div");
-
-
-
- !tags.indexOf("<opt")&& [1, "<select
- multiple='multiple'>","</select>"]
-
- || !tags.indexOf("<leg")&& [1, "<fieldset>", "</fieldset>"]
-
- || tags.match(/^<(thead|tbody|tfoot|colg|cap)/)
- && [1, "<table>", "</table>"]
-
- || !tags.indexOf("<tr")&& [2, "<table><tbody>", "</tbody></table>"]
-
- (!tags.indexOf("<td") || !tags.indexOf("<th"))&& [3,
- "<table><tbody><tr>","</tr></tbody></table>"]
-
- || !tags.indexOf("<col")&& [2,
- "<table><tbody></tbody><colgroup>","</colgroup></table>"]
-
- || jQuery.browser.msie&& [1, "div<div>", "</div>"]
-
- || [0, "", ""];
-
-
- div.innerHTML = wrap[1] + elem + wrap[2];
-
- while (wrap[0]--)
-
- div = div.lastChild;
-
-
- if (jQuery.browser.msie) {
-
-
-
- var tbody = !tags.indexOf("<table")&& tags.indexOf("<tbody") < 0
- ? div.firstChild&& div.firstChild.childNodes
- : wrap[1] == "<table>"&& tags.indexOf("<tbody") < 0
- ? div.childNodes: [];
-
- for (var j = tbody.length - 1;j >= 0; --j)
- if (jQuery.nodeName(tbody[j],
- "tbody")&&!tbody[j].childNodes.length) tbody[j].parentNode.removeChild(tbody[j]);
-
-
- if (/^\s/.test(elem)) div.insertBefore(context.createTextNode
- (elem.match(/^\s*/)[0]),div.firstChild);
- }
-
- elem = jQuery.makeArray(div.childNodes);
- }
-
-
- if (elem.length === 0&& (!jQuery.nodeName(elem, "form")
- && !jQuery.nodeName(elem, "select")))
- return;
-
- if (elem[0] == undefined|| jQuery.nodeName(elem, "form")|| elem.options)
- ret.push(elem);
- else
- ret = jQuery.merge(ret, elem);
- });
-
- return ret;
- },
- 在上面的代码中,我们可以看出对于elems, context的参数的支持是多种形式的,elems可以为(类)数组的形式,还可以采用对象的形式。数组中的元素或对象的属性可以是混合形的,如string,ojbect,甚至(类)数组的形式。对于数字类型,会转换在string形,除string形之外的都放入返回的数组中,当然对于集合的形式,那就会取集合中每个元素。
- 对于string的形式就转换成Dom元素的形式,之后存到返回的数组中。这是这个函数的主要任务。对于把html转换成Dom元素,这里采用innerHTML把html挂到Dom文档树中。这样就转换成了Dom元素。
- 有些html标签片断是有约束的,比如<td>xx</td>,它必须存在table的tr中,也就是说在要进行html的标签片断的修正。这也是上面的代码处理的重点。
- 3.2间接引用Dom节点
- 在init的参数中,我们可以直接输入Dom元素(集)的参数来构建jQuery对象,那么这些Dom元素(集)从那里来的呢?我们可以通过直接引用节点的方式如:document.getElementById,或getElementsByTag来引用Dom元素节点。我们还可以通过dom元素的我们可以通过元素的childNodes firstChild、lastChild、nextSibling、parentNode、previousSibling等间接来取得,等类似的属性来引用元素。因为这个不是直接在Dom中查找的,称为间接引用。
- stChild、parentNode这些都是Dom元素的属性,jquery对象是Dom元素的集合。它也应该把这些间接引用的属性整合到jquery对象中来,这样就可以通过jquery对象来获得其集合中所有元素的各自的间接引用节点。把这些间接引用 的节点组合起来构成新的集合。集合中元素是jquery对象所有的元素的子节点或父节点之类的间接引用节点。
- 有了这些节点集合,可以作为jQuery.fn.init的参数传入。有人会问连这jQuery.fn.init都没有完成,怎么可能通过jquery对象而得到间接引用节点(集)呢?
- 第一、因为jQuery.fn.init的参数可以有四个类型,我们完全可以通过String类型来先构建Jquery对象(html生成Dom对象,#id的getElementById直接引用,CSS Selector)。然后就可以把这个对象的间接引用到的元素节点作为参数传给下一个要构建的jquery对象。很多调用pushStack函数的用法就是这样的。
- 第二、如果硬是要不脱离jQuery来进行间接引用的话,jQuery提供几个静态方法:jQuery.dir、jQuery.nth、jQuery.sibling来完成间接引用。既然是间接引用,当然得先有一个dom元素的主体。直接引用也有主体,但是我们可以采用document来做为默认的。因为直接引用是查找的方式。
- jQuery.each( {
- parent : function(elem) {
- return elem.parentNode;
- },
- parents : function(elem) {
- return jQuery.dir(elem, "parentNode");
- },
- next : function(elem) {
- return jQuery.nth(elem, 2, "nextSibling");
- },
- prev : function(elem) {
- return jQuery.nth(elem, 2, "previousSibling");
- },
- nextAll : function(elem) {
- return jQuery.dir(elem, "nextSibling");
- },
- prevAll : function(elem) {
- return jQuery.dir(elem, "previousSibling");
- },
- siblings : function(elem) {
- return jQuery.sibling(elem.parentNode.firstChild, elem);
- },
- children : function(elem) {
- return jQuery.sibling(elem.firstChild);
- },.. .. .. },
- function(name, fn) {
- jQuery.fn[name] = function(selector) {
- var ret = jQuery.map(this, fn);
- if (selector && typeof selector == "string")
- ret = jQuery.multiFilter(selector, ret);
- return this.pushStack(jQuery.unique(ret));
- };
- });
- 这段代码就是jQuery对象的间接引用节点的方法。它提供了父节点、子节点,兄弟节点三个方法的操作。对于父节点,可以可得到其当前的父亲节点,还可以得到所有父亲节点(包括祖先节点)。对于子节点,就是所有的直接的子节点(不包括其它的后代节点)。对于兄弟节点,有大(前面)兄弟节点(们)和小(后面)兄弟节点(们)之分。
- 接下就是把这八个节点注册到jQuery.fn(即jQuery对象)中的同名方法中。因为jQuery对象的Dom元素是集合,那么就得对集合中每个Dom元素都要进行单个元素相同的操作(上面8种的间接引用节点的Fn)。在组合中,有可能会有重复的dom元素,也还有可能用户会对这些间接引用节点进行其它的自定义的过滤。这里支持的过滤方式下一小节要分析的selector的过滤。最后构建一个新的jQuery对象。
- 其调用的方式如:$(‘p’). parents()。这个例子是所有p标签的所有父辈(包含祖先)节点的所组合而成的集合。这个集合有重复的元素可能性是很大。所以要jQuery.unique(ret)来进行过滤。
- 再举一个例子:$(‘p’). parents(“div”)。这个就是取所有所有父辈(包含祖先)节点中的Tagname为div的元素集合。这个就采用了CSS的过滤。最后还是要进行unique处理。
- 在上面的代码,我们也看到了几个静态间接引用节点的函数调用:
-
- dir : function(elem, dir) {
- var matched = [], cur = elem[dir];
- while (cur && cur != document) {
- if (cur.nodeType == 1)
- matched.push(cur);
- cur = cur[dir];
- }
- return matched;
- },
- 取名dir,我们会想到Dos的Dir操作。其实我们解释为direction(方向)更好理解。它一直会朝着方向走到尽头。如parentNode的方向。它会把取的父节点作为当前节点再取其父节点。就是所有的父辈节点(们)。对于nextSibling、previousSibling、lastChild,firstChild都一样。只要取到的元素有dir这个方向(属性)的话,就一直取下去。每一步都会把取到的元素保存起来。这个函数是对于要取‘一条线’形式的Dom文档树的所有元素是有很有用的。从一个元素出发,其parentNode可以画一条线,lastChild也可以画一条线。当然nextSibling不也类外。
- Dir是取某一个方向上所有的元素,有的时候,我们要取的是某一个方向上的第几个元素,如我们找到其爷爷节点。那就是某一个方向上的第二个元素。下面的nth就是实现这个功能。
-
- nth : function(cur, result, dir, elem) {
- result = result || 1;
- var num = 0;
- for (;cur; cur = cur[dir])
- if (cur.nodeType == 1 && ++num == result)
- break;
- return cur;
- },
- Nth与dir在一个方向有点不同的地方,就是dir不包含自身,而nth包含自身,如果result是1的话,那是自身的元素。如果没有找到就返回空(有可能是undifined,或null)。
- 接下来的sibling就比较简单,但是用途也会少很多。它实现从一个元素(包括自身)找到其所有后续兄弟(们),然后从这个后续的兄弟(们)排除一个指的元素。
-
- sibling : function(n, elem) {
- var r = [];
- for (;n; n = n.nextSibling) {
- if (n.nodeType == 1 && n != elem)
- r.push(n);
- }
- return r;
- }
- 仔细想一下,没有什么好适用的场合,但是jquery.fn.siblings中的用法倒是最合适的用法。找到自己的所有兄弟。找自己的所有兄弟最好的方法当然是找到父亲节点,然后排除自身节点。采用childNodes再查找当前元素并去掉和这个操作差不多,效率应该会高点。
posted @
2008-12-02 18:05
瑞尼书苑
阅读(
1041)
评论()
编辑
收藏
举报