第二章 jQuery技术解密 (四)

2.3.4 生成 DOM 元素

jQuery.fn.init() 构造函数能够构建 jQuery 对象,并把匹配的 DOM 元素存储在 jQuery 对象内部集合中。jQuery.fn.init() 构造函数可以接收单个的 DOM 元素,也可以接收 DOM 集合。如果接收的是字符串型 ID 值,则直接在文档中查找对应的 DOM 元素,并把它传递给 jQuery 对象;如果接收的是字符串型 HTML 片段,则需要把这个字符串片段生成 DOM 元素。下面我们将重点分析 jQuery 是如何把 HTML 片段生成 DOM 元素的。

在2.3.3节中,我们可以看到 jQuery.fn.init() 构造器通过 jQuery.clean([match[1], context]); 语句实现把 HTML 片段生成 DOM 元素,jQuery.clean() 是一个公共函数。源代码及其注释如下所示。

jQuery.clean() 包含三个参数,其中 elems 和 context 可以支持多种形式的值。Elems 参数可以为数组、类数组、对象结构的形式。数组元素和对象属性可以混合使用。

对于数字类型参数,则会被转换为字符串型,除了字符串型外,其他的都放入返回的数组中,当然对于集合形式只需要读取集合中每个元素即可。

对于字符串型参数,则把它转换成 DOM 元素,再存入返回的数组中。转换的方式是,把 HTML 字符串片段赋值给创建的 div 元素的 innerHTML ,这样就可以把 HTML 字符串片段挂到 DOM 文档树中,从而实现把字符串转换成 DOM 元素。

在转换过程中,应该考虑 HTML 语法约定,因为标签嵌套是有严格限制的,例如,<td> 必须存在 <tr> 中。因此在执行转换前,还应该对 HTML 字符串进行预处理,即修正 HTML 标签不规范的用法,这也是 jQuery.clean() 函数的一个重要工作。

[html]view
plain
copy

  1. <scripttype="text/javascript">
  2. (function(){
  3. var
  4. window=this,
  5. jQuery=window.jQuery=window.$=function(selector,context){
  6. returnnewjQuery.fn.init(selector,context);
  7. },
  8. quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/;
  9. jQuery.fn=jQuery.prototype={
  10. init:function(selector,context){
  11. selector=selector||document;
  12. if(typeofselector=="string"){
  13. varmatch=quickExpr.exec(selector);
  14. if(match&&(match[1]||!context)){
  15. //第二种情况,处理HTML字符串,类似$(html)->$(array)
  16. if(match[1]){
  17. selector=jQuery.clean([match[1]],context);
  18. }
  19. }
  20. }
  21. }
  22. };
  23. jQuery.fn.init.prototype=jQuery.fn;
  24. //jQuery功能扩展函数
  25. jQuery.extend=jQuery.fn.extend=function(obj){
  26. for(varpropinobj){
  27. this[prop]=obj[prop];
  28. }
  29. returnthis;
  30. };
  31. //公共函数扩展
  32. jQuery.extend({
  33. //参数说明:object表示jQuery对象,callback表示回调函数,args回调函数的参数数组
  34. each:function(object,callback,args){
  35. varname,i=0,length=object.length;
  36. if(args){//如果存在回调函数的参数数组
  37. if(length===undefined){//如果object不是jQuery对象
  38. for(nameinobject){//遍历object的属性
  39. if(callback.apply(object[name],args)===false)
  40. //在对象上调用回调函数
  41. break;//如果回调函数返回值为false,则跳出循环
  42. }
  43. }else{
  44. for(;i<length;)//遍历jQuery对象数组
  45. if(callback.apply(object[i++],args)===false)
  46. //在对象上调用回调函数
  47. break;//如果回调函数返回值为false,则跳出循环
  48. }
  49. }else{
  50. if(length===undefined){//如果object不是jQuery对象
  51. for(nameinobject)//遍历object的属性
  52. if(callback.call(object[name],name,object[name])===false)
  53. break;//如果回调函数返回值为false,则跳出循环
  54. }else{//如果object是jQuery对象
  55. for(varvalue=object[0];//遍历jQuery对象数组
  56. i<length&&callback.call(value,i,value)!==false;value=object[++i]){}
  57. }
  58. }
  59. },
  60. //把HTML字符串片段转换成DOM元素
  61. //参数说明:
  62. //elems参数表示多个HTML字符串片段的数据
  63. //context参数表示上下文
  64. //fragment参数表示框架对象
  65. clean:function(elems,context,fragment){
  66. context=context||document;//默认的上下文是document
  67. //在IE中!context.createElement是错误用法,因为它返回的是对象类型,而不是逻辑值,
  68. //故通过返回类型进行判断
  69. if(typeofcontext.createElement=="undefined")
  70. //支持context为jQuery对象,并获取第一个元素
  71. context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;
  72. //如果仅匹配一个标签,且没有指定框架参数,则直接创建DOM元素,并跳过后面的解析
  73. if(!fragment&&elems.length===1&&typeofelems[0]==="string"){
  74. varmatch=/^<(\w+)\s*\/?>$/.exec(elems[0]);
  75. if(match)
  76. return[context.createElement(match[1])];
  77. }
  78. varret=[],scripts=[],div=context.createElement("div");
  79. //匹配每一个HTML字符串片段,并为每一个片段执行回调函数
  80. jQuery.each(elems,function(i,elem){
  81. if(typeofelem==="number")//把数值转换为字符串的高效方法
  82. elem+='';
  83. if(!elem)//如果不存在元素,则返回,或者为''、undefined、false等时也返回
  84. return;
  85. //HTML字符串转换为DOM节点
  86. if(typeofelem==="string"){
  87. //统一转换为XHTML严谨型文档的标签形式,如<div/>的形式修改为<div></div>
  88. //但是对于(abbr|br|col|img|input|link|meta|param|hr|area|embed)不修改
  89. //front=(<(\w+)[^>]*?)--非贪婪的重复
  90. elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){
  91. //all--匹配项
  92. //front--第一个捕获组
  93. //tag--第二个捕获组
  94. returntag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?
  95. all:
  96. front+"></"+tag+">";
  97. });
  98. //清除空格,否则indexof可能会出现不能正常工作,elem.replace(/^\s+/,"")清除左侧空格
  99. vartags=elem.replace(/^\s+/,"").substring(0,10).toLowerCase();
  100. //有些标签必须是有一些约束的,如<option>必须在<select></select>中间
  101. //下面代码大部分是对<table>中的子元素进行修正。数组中第一个元素为深度
  102. varwrap=
  103. //约束<option>,<opt在开始位置(index=0)就返回&&运算符后面的数组(!0返回true)
  104. !tags.indexOf("<opt")&&
  105. [1,"<selectmultiple='multiple'>","</select>"]||
  106. //<leg必须在<fieldset>内部
  107. !tags.indexOf("<leg")&&
  108. [1,"<fieldset>","</fieldset>"]||
  109. //thead|tbody|tfoot|colg|cap必须在<table>内部
  110. tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&
  111. [1,"<table>","</table>"]||
  112. //tr在<tbody中间
  113. !tags.indexOf("<tr")&&
  114. [2,"<table><tbody>","</tbody></table>"]||
  115. //td在tr中间
  116. (!tags.indexOf("<td")||!tags.indexOf("<th"))&&
  117. [3,"<table><tbody><tr>","</tr></tbody></table>"]||
  118. //col在<colgroup>中间
  119. !tags.indexOf("<col")&&
  120. [2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||
  121. //IE中link,script不能串行化
  122. //IEcan'tserialize<link>and<script>tagsnormally
  123. !jQuery.support.htmlSerialize&&
  124. [1,"div<div>","</div>"]||
  125. //默认不修正
  126. [0,"",""];
  127. //包裹HTML之后,采用innerHTML转换成DOM
  128. div.innerHTML=wrap[1]+elem+wrap[2];
  129. //转到正确的深度,对于[1,"<table>","</table>"],div=<table>
  130. while(wrap[0]--)
  131. div=div.lastChild;
  132. //fragments去掉IE对<table>自动插入的<tbody>
  133. //if(!jQuery.support.tbody){
  134. //第一种情况:tags以<table>开头但没有<tbody>。在IE生成的元素中可能自动加<tbody>
  135. //第二种情况:thead|tbody|tfoot|colg|cap为tags,那wrap[1]=="<table>"
  136. //TODO
  137. //}
  138. //使用innerHTML,IE会去掉开头的空格节点,因此加上去掉的空格节点
  139. //TODO
  140. //elem从字符转换成了数组
  141. //TODO
  142. }
  143. //如果是DOM元素,则推入数组,否则就合并数组
  144. /*if(elem.nodeType)
  145. ret.push(elem);
  146. else
  147. ret=jQuery.merge(ret,elem);*/
  148. });
  149. //如果指定了第3个参数,即框架对象,则附加到框架对象上
  150. //这段是新增加的,用来处理js代码,同时也取消了form的处理
  151. if(fragment){
  152. //TODO
  153. }
  154. //返回DOM元素集合
  155. returnret;
  156. }
  157. });
  158. })();
  159. window.onload=function(){
  160. varcontext=document.getElementById("wrap");
  161. //测试代码
  162. $("<option/><div/>",context);
  163. };
  164. </script>

上面这段代码实际上最后访问的是一个名为 ret 的数组,数组中的元素变为 DOM 元素的对象,而它的 innerHTML 正好就是刚才的 HTML 字符串。

时间: 2024-08-01 03:39:36

第二章 jQuery技术解密 (四)的相关文章

第二章 jQuery技术解密 (二)

2.2.6 延续 -- 迭代器 在 jQuery 框架中,jQuery 对象是一个很奇怪的概念,具有多重身份,所以很多初学者一听说 jQuery 对象就感觉很是不解,误以为它是 John Resig 制造的新概念.我们可以对jQuery 对象进行如下分解. 第一,jQuery 对象是一个数据集合,它不是一个个体对象.因此,你无法直接使用 JavaScript 的方法来操作它. 第二,jQuery 对象实际上就是一个普通的对象,因为它是通过 new 运算符创建的一个新的实例对象.它可以继承原型方法

第二章 jQuery技术解密(一)

2.2 jQuery 原型技术分解 任何复杂的技术都是从最简单的问题开始的,如果你被 jQuery 几千行庞杂结构的源代码所困惑,那么建议你阅读本节内容,我们将探索 jQuery 是如何从最简单的问题开始,并逐步实现羽翼渐丰的演变过程,从 jQuery 核心技术的还原过程来理解 jQuery 框架的搭建原理. 2.2.1 起源 -- 原型继承 用过 JavaScript 的读者都会明白,在 JavaScript 脚本中到处都是函数,函数可以归置代码段,把相对独立的功能封装在一个函数包中.函数也可

第二章 jQuery技术解密 (六)

2.4 解析 jQuery 选择器引擎 Sizzle jQuery 从 1.3 版本开始,使用了新的选择器引擎 Sizzle(官方网址 http://sizzlejs.com) .Sizzle 是 jQuery 作者 John Resig 开发的 DOM 选择器引擎 (Dom Selector Engine),速度号称业界第一.而且它有一个重要的特点就是 Sizzle 是完全独立于 jQuery 的,如果用户不想用 jQuery ,还可以只用 Sizzle . Sizzle 选择器引擎目前成为

第二章 jQuery技术解密 (七)

2.4.5 Sizzle 构造器 在 jQuery.fn.init() 构造器中,通过调用 jQuery(context).find(selector) 函数来解析并匹配 DOM 元素.jQuery.find() 函数实际上是引用 Sizzle() 函数,而 Sizzle() 函数仅是 Sizzle 引擎的构造器,它主要调用 Sizzle.find() 函数在 DOM 文档树中查找与 CSS 语法相匹配 DOM 的元素节点的集合.jQuery 名字中 Query 的意义就体现在这里.下面我们来分

第二章 jQuery技术解密 (五)

2.3.5 引用 DOM 元素 jQuery() 函数能够直接接受 HTML 字符串,并把它们转换为 DOM 结构,这是上一节中所讲解的利用 jQuery() 函数生成 DOM 元素.当然,我们也可以看到 jQuery() 函数还可以接收 DOM 元素.DOM元素集合.HTML标签或者 ID 值.下面我们就来分析 jQuery.fn.init() 构造器是如何把这些类型的参数转换为 DOM 元素的. 对于 HTML 标签来说,它使用 document.getElementsByTagName()

&amp;gt; 第二章 NGWS Runtime 技术基础(rainbow 翻译) (转自重粒子空

<<展现C#>> 第二章 NGWS Runtime 技术基础(rainbow 翻译)   出处:http://www.informit.com/matter/ser0000001/chapter1/ch02.shtml 正文: 第二章  NGWS  runtime 技术基础     既然你已经具有了C#全面的印象,我也想让你了解NGWS runtime的全貌.C#依靠由NGWS提供的运行时:因此,有必要知道运行时如何工作,以及它背后所蕴含的概念.    所以,这一章分为两部分--它

《众妙之门——JavaScript与jQuery技术精粹》——第1章 初学JavaScript 需知的七件事 1.1 缩略标记

第1章 初学JavaScript 需知的七件事 我很早以前就开始编写JavaScript代码,很高兴看到这种语言在今天所取得的成功,能成为这个成功故事中的一部分我很开心.关于JavaScript,我写过许多文章.章节以及一整本书,直到今天我仍在寻找新的东西.下文是一些我工作学习过程中激动时刻的记录,大家与其守株待兔,不如自己尝试去体会这种感受. 1.1 缩略标记 众妙之门--JavaScript与jQuery技术精粹 在创建对象和数组过程中可以使用缩略标记是我喜欢JavaScript的重要原因之

Google--PageRank技术解密(四)

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 Google-- PageRank技术解密(四)   14. 网站内部结构和联结  15. Google如是说  16. 结束语   十四:网站的内部结构和联接  一:网站的内部页面  说完了" 外部链接",现在让我们来看看"内部链接".如果PageRank确由页面投票的质量和数量所决定,那么我们立即就

jQuery技术内幕:深入解析jQuery架构设计与实现原理1

jQuery技术内幕:深入解析jQuery架构设计与实现原理 高 云 著 图书在版编目(CIP)数据 jQuery技术内幕:深入解析jQuery架构设计与实现原理 / 高云著. -北京:机械工业出版社,2013.11 ISBN 978-7-111-44082-6 I. j- II. 高- III. JAVA语言-程序设计 IV. TP312 中国版本图书馆CIP数据核字(2013)第221662号 版权所有·侵权必究 封底无防伪标均为盗版 本书法律顾问 北京市展达律师事务所     本书由阿里巴