`
jljlpch
  • 浏览: 323969 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

如何找到Dom元素

阅读更多
3、如何找到Dom元素
                                                    prk/彭仁夔       08-08-19
在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元素,这是一个静态方法:
// 把html转换成Dom元素,elems多个html string 的数组
clean : function(elems, context) {
	  var ret = [];
	  context = context || document;//默认的上下文是document
	  //在IE中!context.createElement行不通,因为它返回对象类型
	  if (typeof context.createElement == 'undefined')
			//这里支持context为jQuery对象,取第一个元素。
		context = context.ownerDocument || context[0]
						&& context[0].ownerDocument || document;

	jQuery.each(elems, function(i, elem) {
// 把int 转换成string的最高效的方法
		if (typeof elem == 'number')elem += '';
		if (!elem)	return;// 为'',undefined,false等时返回
		if (typeof elem == "string") {// 转换html为Dom元素
		// 修正 "XHTML"-style 标签,对于如<div/>的形式修改为<div></div>
		    //但是对于(abbr|br|col|img|input|link|meta|param|hr|area|embed)
//不修改	 。front=(<(\w+)[^>]*?)
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+ ">";}	);
		// 去空格,否则indexof可能会出不能正常工作
		var tags = jQuery.trim(elem).toLowerCase(), 
		div = context.createElement("div");//在上下文中创建了一个元素<div>
		// 有些标签必须是有一些约束的,比如<option>必须在<select></select>中间
		// 下面的代码在大部分是对<table>中子元素进行修正。数组中第一个元素为深度			var wrap = 
//<opt在开始的位置上(index=0)就返回&&后面的数组,这是对<option>的约束
!tags.indexOf("<opt")&& [1, "<select 
multiple='multiple'>","</select>"]
	//<leg 必须在<fieldset>内部
	|| !tags.indexOf("<leg")&& [1, "<fieldset>", "</fieldset>"]
	//thead|tbody|tfoot|colg|cap必须在<table>内部
	||  tags.match(/^<(thead|tbody|tfoot|colg|cap)/)
&& [1, "<table>", "</table>"]
     //<tr在<tbody>中间
	|| !tags.indexOf("<tr")&& [2, "<table><tbody>", "</tbody></table>"]
	 //td在tr中间
	 (!tags.indexOf("<td") || !tags.indexOf("<th"))&& [3, 
"<table><tbody><tr>","</tr></tbody></table>"]
	 //col在<colgroup>中间
	|| !tags.indexOf("<col")&& [2, 
"<table><tbody></tbody><colgroup>","</colgroup></table>"]
	 //IE中 link script不能串行化 ?
	|| jQuery.browser.msie&& [1, "div<div>", "</div>"]
	 //默认不修正
	|| [0, "", ""];

	// 包裹html之后,采用innerHTML转换成Dom
	div.innerHTML = wrap[1] + elem + wrap[2];

	while (wrap[0]--)
	// 转到正确的深度,对于[1, "<table>","</table>"],div=<table>
		div = div.lastChild;

	// fragments去掉IE对<table>自动插入的<tbody>
	if (jQuery.browser.msie) {								
	// 第一种情况:tags以<table>开头但没有<tbody>。在IE中生成的元素中可能会自动
// 加的<tbody> 第二种情况:thead|tbody|tfoot|colg|cap为tags,
// 那wrap[1] == "<table>" .tbody不一定是tbody,也有可能是thead等等
	var tbody = !tags.indexOf("<table")&& tags.indexOf("<tbody") < 0
				 ? div.firstChild&& div.firstChild.childNodes 
				 : wrap[1] == "<table>"&& tags.indexOf("<tbody") < 0
					   ? div.childNodes: [];
	// 除去<tbody>
	 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]);

	//使用innerHTML,IE会去开头的空格节点的,加上去掉的空格节点
	if (/^\s/.test(elem))									 div.insertBefore(context.createTextNode
(elem.match(/^\s*/)[0]),div.firstChild);
	}
                     
	elem = jQuery.makeArray(div.childNodes);//elem从字符转换成了数组
}
      //采用===0,因为form,select都有length属性。这里主要是为了form,select进
//行下面的if else 处理。对于其它的length === 0的,也根本就不要加入到ret中。
if (elem.length === 0&& (!jQuery.nodeName(elem, "form")
				    && !jQuery.nodeName(elem, "select")))
						return;
   //不是(类)数组的形式的元素,或是form元素或是select元素(这两个可以看作类数组)
if (elem[0] == undefined|| jQuery.nodeName(elem, "form")|| elem.options)
		ret.push(elem);
else// 对于elems是array-like的集合
	ret = jQuery.merge(ret, elem);
});
   //上面的each中把有效的元素都加入到ret,现在只要返回就得到转换的Dom元素数组
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) {// elem的所有parentNode
			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对象中去,可以调用同名方法
			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对象的间接引用节点的方法。它提供了父节点、子节点,兄弟节点三个方法的操作。对于父节点,可以可得到其当前的父亲节点,还可以得到所有父亲节点(包括祖先节点)。对于子节点,就是所有的直接的子节点(不包括其它的后代节点)。对于兄弟节点,有大(前面)兄弟节点(们)和小(后面)兄弟节点(们)之分。
接下就是把这八个节点注册到jQuery.fn(即jQuery对象)中的同名方法中。因为jQuery对象的Dom元素是集合,那么就得对集合中每个Dom元素都要进行单个元素相同的操作(上面8种的间接引用节点的Fn)。在组合中,有可能会有重复的dom元素,也还有可能用户会对这些间接引用节点进行其它的自定义的过滤。这里支持的过滤方式下一小节要分析的selector的过滤。最后构建一个新的jQuery对象。
其调用的方式如:$(‘p’). parents()。这个例子是所有p标签的所有父辈(包含祖先)节点的所组合而成的集合。这个集合有重复的元素可能性是很大。所以要jQuery.unique(ret)来进行过滤。
再举一个例子:$(‘p’). parents(“div”)。这个就是取所有所有父辈(包含祖先)节点中的Tagname为div的元素集合。这个就采用了CSS的过滤。最后还是要进行unique处理。
在上面的代码,我们也看到了几个静态间接引用节点的函数调用:
//从一个元素出发,取得一个方向上的所有元素,如parentNode、nextSibling、//previousSibling、lastChild,firstChild这样的元素的属性作为方向(dir).
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就是实现这个功能。
// 取某个方向上的第几个元素。Result是第几个
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就比较简单,但是用途也会少很多。它实现从一个元素(包括自身)找到其所有后续兄弟(们),然后从这个后续的兄弟(们)排除一个指的元素。
// 从包含n元素开始的所有后续兄弟,但不包含elem。
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再查找当前元素并去掉和这个操作差不多,效率应该会高点。

 

分享到:
评论
1 楼 lipeng88213 2010-10-19  
引用
context = context.ownerDocument || context[0] 
                        && context[0].ownerDocument || document;


楼主能解释一下这个的用处吗 谢谢

相关推荐

    在vue中获取dom元素内容的方法

    "在 Vue 中获取 DOM 元素内容的方法" 在 Vue 中获取 DOM 元素内容是开发者经常遇到的问题,而解决这个问题的方法很多,今天我们就来讨论其中的一种,即使用 ref 属性来获取 DOM 元素内容。 使用 ref 属性获取 DOM ...

    Jquery方式获取iframe页面中的 Dom元素

    为了获取iframe中的DOM元素,我们可以通过jQuery来实现这一目标。在具体的实现过程中,需要注意iframe中的内容必须和主页面出于同一个域中,否则会受到浏览器同源策略的限制,无法获取到其中的DOM元素。这是因为...

    jQuery鼠标拖动旋转DOM元素插件

    在DOM元素上应用Propeller.js插件,需要使用jQuery选择器找到目标元素,然后调用`.propeller()`方法。这个方法允许设置一些参数来自定义旋转行为,如旋转速度、灵敏度等。 ```javascript $(document).ready...

    准确找到DOM树的元素

    在实际开发中,工具的使用也是寻找DOM元素的重要手段。例如,Chrome开发者工具和Firefox的Web Console提供了强大的DOM查看和操作功能。它们允许开发者实时查看DOM结构,选中元素,查看其属性,甚至修改元素内容和...

    chrome根据dom找到dom上的事件.zip

    本教程将围绕“如何在Chrome中根据DOM找到DOM上的事件”这一主题展开,结合"Event Listeners.png"这个图片文件,我们将详细讨论这一过程。 首先,打开Chrome浏览器,按下F12键或右键点击页面并选择"检查"以打开...

    AJAX开发简略ajax基础教程DOM操作

    2. **节点操作**:通过`document.getElementById()`, `getElementsByTagName()`, `querySelector()`等方法找到DOM元素。然后,可以使用`appendChild()`, `removeChild()`, `innerHTML`等属性和方法来操作这些元素。 ...

    头歌教学实践平台 Web前端开发基础 JavaScript学习手册十四:HTML DOM-文档元素的操作(二)

    在这个部分,我们将学习更多关于DOM元素操作的方法和技巧。 首先,`getElementById()`是获取特定ID元素的常用方法。通过这个方法,我们可以直接根据元素的ID找到它,并对其进行操作,例如改变其内容、样式或属性。...

    25 完成工作单元创建 DOM 元素实例与收集副作用慕课专栏1

    本节主要关注的是在完成工作单元时React执行的两个关键任务:创建DOM元素实例以及收集副作用(Effect List)。 完成工作单元的入口函数是`completeUnitOfWork`。这个函数按照自底向上的顺序遍历Fiber树,从子节点...

    基于ES6的DOM元素动画库插件.zip

    在这个“基于ES6的DOM元素动画库插件.zip”文件中,我们很可能会找到一个利用这些新特性实现的高效且灵活的动画库。 首先,让我们关注HTML5这个标签。HTML5引入了许多新的标签和API,比如`&lt;canvas&gt;`用于绘制图形,...

    jQuery知识点.docx

    `$("#first")` 通过 ID 直接找到 DOM 元素,`.html()` 用于获取或设置元素的 HTML 内容。将 DOM 对象转换为 jQuery 对象,只需使用 `$()` 包裹 DOM 对象;反之,jQuery 对象通过 `[index]` 下标可以获取对应的 DOM ...

    WEB开发 之 JavaScript HTML DOM 元素(节点).docx

    本文将详细讲解如何使用JavaScript操作HTML DOM元素。 首先,要向HTML DOM添加新元素,你需要创建这个元素。例如,以下代码创建了一个新的`&lt;p&gt;`元素: ```javascript var para = document.createElement('p'); ```...

    DOM元素简介[文].pdf

    例如,可以找到特定ID的元素,改变其样式,添加新的子元素,或者响应用户的交互事件。DOM使得动态网页成为可能,它允许开发者在页面加载后修改内容,实现诸如动画效果、交互式表单验证等功能。 W3C(全球信息网协会...

    elementPresence:仅在页面中找到元素时才运行代码

    元素存在是一个简单的函数,用于在页面中找到DOM元素时解决承诺。 该函数不仅查找作为参数提供的特定选择器,还侦听DOM中的任何后续更改,这些更改可能导致注入我们在页面中寻找的DOM元素。 它还可以捕获DOM元素...

    jquery+纯生javascript写的适合初学者

    它的核心概念包括选择器(用于找到DOM元素)、链式调用(返回jQuery对象以连续执行方法)和方法(如`$(document).ready()`用于在页面加载完成后执行代码)。jQuery还提供了一些实用功能,如`$.ajax`用于处理Ajax请求...

    JQuery教程源码

    在jQuery中,通过选择器找到DOM元素,并进行操作,如添加、删除或改变元素的属性、样式和内容。 ### 操作得到的元素 jQuery提供了一套简洁的API,使得操作DOM元素变得简单。例如,`$(selector)`用于选择元素,`....

    dom教程 dom文档对象实例教程

    1. **DOM操作**:利用JavaScript直接操作DOM元素,如查找、创建、修改和删除元素。 2. **DOM事件**:使用JavaScript处理用户交互,如点击、鼠标移动、键盘输入等。 3. **DOM动画**:通过改变DOM元素的属性实现平滑的...

    jquery rotate图片旋转插件制作转盘360度旋转抽奖代码.zip

    首先,jQuery的核心功能包括选择器(用于快速找到DOM元素)、DOM操作(如添加、删除或修改元素)、事件处理(绑定和触发事件)和动画(提供平滑的页面效果)。在旋转抽奖应用中,jQuery的选择器和DOM操作功能将用于...

    JavaScript获取HTML DOM节点元素的方法的总结

    在实际应用中,开发者通常会结合这些方法来定位和操作特定的DOM元素。例如,先通过`getElementById`找到一个父节点,然后使用`getElementsByTagName`或`children`来筛选出特定类型的子元素,最后利用`...

    CSS3小球浮动按钮.zip

    1. **选择器**:更简洁的选择器语法,快速找到DOM元素。 2. **DOM操作**:提供方便的方法来操作DOM元素,如`.append()`、`.remove()`等。 3. **事件处理**:绑定和解绑事件,如`.click()`、`.hover()`等。 4. **动画...

Global site tag (gtag.js) - Google Analytics