第二章 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() 函式的一個重要工作。
- <scripttype="text/javascript">
- (function(){
- var
- window=this,
- jQuery=window.jQuery=window.$=function(selector,context){
- returnnewjQuery.fn.init(selector,context);
- },
- quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/;
- jQuery.fn=jQuery.prototype={
- init:function(selector,context){
- selector=selector||document;
- if(typeofselector=="string"){
- varmatch=quickExpr.exec(selector);
- if(match&&(match[1]||!context)){
- //第二種情況,處理HTML字串,類似$(html)->$(array)
- if(match[1]){
- selector=jQuery.clean([match[1]],context);
- }
- }
- }
- }
- };
- jQuery.fn.init.prototype=jQuery.fn;
- //jQuery功能擴充套件函式
- jQuery.extend=jQuery.fn.extend=function(obj){
- for(varpropinobj){
- this[prop]=obj[prop];
- }
- returnthis;
- };
- //公共函式擴充套件
- jQuery.extend({
- //引數說明:object表示jQuery物件,callback表示回撥函式,args回撥函式的引數陣列
- each:function(object,callback,args){
- varname,i=0,length=object.length;
- if(args){//如果存在回撥函式的引數陣列
- if(length===undefined){//如果object不是jQuery物件
- for(nameinobject){//遍歷object的屬性
- if(callback.apply(object[name],args)===false)
- //在物件上呼叫回撥函式
- break;//如果回撥函式返回值為false,則跳出迴圈
- }
- }else{
- for(;i<length;)//遍歷jQuery物件陣列
- if(callback.apply(object[i++],args)===false)
- //在物件上呼叫回撥函式
- break;//如果回撥函式返回值為false,則跳出迴圈
- }
- }else{
- if(length===undefined){//如果object不是jQuery物件
- for(nameinobject)//遍歷object的屬性
- if(callback.call(object[name],name,object[name])===false)
- break;//如果回撥函式返回值為false,則跳出迴圈
- }else{//如果object是jQuery物件
- for(varvalue=object[0];//遍歷jQuery物件陣列
- i<length&&callback.call(value,i,value)!==false;value=object[++i]){}
- }
- }
- },
- //把HTML字串片段轉換成DOM元素
- //引數說明:
- //elems參數列示多個HTML字串片段的資料
- //context參數列示上下文
- //fragment參數列示框架物件
- clean:function(elems,context,fragment){
- context=context||document;//預設的上下文是document
- //在IE中!context.createElement是錯誤用法,因為它返回的是物件型別,而不是邏輯值,
- //故通過返回型別進行判斷
- if(typeofcontext.createElement=="undefined")
- //支援context為jQuery物件,並獲取第一個元素
- context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;
- //如果僅匹配一個標籤,且沒有指定框架引數,則直接建立DOM元素,並跳過後面的解析
- if(!fragment&&elems.length===1&&typeofelems[0]==="string"){
- varmatch=/^<(\w+)\s*\/?>$/.exec(elems[0]);
- if(match)
- return[context.createElement(match[1])];
- }
- varret=[],scripts=[],div=context.createElement("div");
- //匹配每一個HTML字串片段,併為每一個片段執行回撥函式
- jQuery.each(elems,function(i,elem){
- if(typeofelem==="number")//把數值轉換為字串的高效方法
- elem+='';
- if(!elem)//如果不存在元素,則返回,或者為''、undefined、false等時也返回
- return;
- //HTML字串轉換為DOM節點
- if(typeofelem==="string"){
- //統一轉換為XHTML嚴謹型文件的標籤形式,如<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){
- //all--匹配項
- //front--第一個捕獲組
- //tag--第二個捕獲組
- returntag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?
- all:
- front+"></"+tag+">";
- });
- //清除空格,否則indexof可能會出現不能正常工作,elem.replace(/^\s+/,"")清除左側空格
- vartags=elem.replace(/^\s+/,"").substring(0,10).toLowerCase();
- //有些標籤必須是有一些約束的,如<option>必須在<select></select>中間
- //下面程式碼大部分是對<table>中的子元素進行修正。陣列中第一個元素為深度
- varwrap=
- //約束<option>,<opt在開始位置(index=0)就返回&&運算子後面的陣列(!0返回true)
- !tags.indexOf("<opt")&&
- [1,"<selectmultiple='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不能序列化
- //IEcan'tserialize<link>and<script>tagsnormally
- !jQuery.support.htmlSerialize&&
- [1,"div<div>","</div>"]||
- //預設不修正
- [0,"",""];
- //包裹HTML之後,採用innerHTML轉換成DOM
- div.innerHTML=wrap[1]+elem+wrap[2];
- //轉到正確的深度,對於[1,"<table>","</table>"],div=<table>
- while(wrap[0]--)
- div=div.lastChild;
- //fragments去掉IE對<table>自動插入的<tbody>
- //if(!jQuery.support.tbody){
- //第一種情況:tags以<table>開頭但沒有<tbody>。在IE生成的元素中可能自動加<tbody>
- //第二種情況:thead|tbody|tfoot|colg|cap為tags,那wrap[1]=="<table>"
- //TODO
- //}
- //使用innerHTML,IE會去掉開頭的空格節點,因此加上去掉的空格節點
- //TODO
- //elem從字元轉換成了陣列
- //TODO
- }
- //如果是DOM元素,則推入陣列,否則就合併陣列
- /*if(elem.nodeType)
- ret.push(elem);
- else
- ret=jQuery.merge(ret,elem);*/
- });
- //如果指定了第3個引數,即框架物件,則附加到框架物件上
- //這段是新增加的,用來處理js程式碼,同時也取消了form的處理
- if(fragment){
- //TODO
- }
- //返回DOM元素集合
- returnret;
- }
- });
- })();
- window.onload=function(){
- varcontext=document.getElementById("wrap");
- //測試程式碼
- $("<option/><div/>",context);
- };
- </script>
相關文章
- 第二章 jQuery技術解密(一)jQuery解密
- 第二章 jQuery技術解密 (二)jQuery解密
- 第二章 jQuery技術解密 (三)jQuery解密
- 第二章 jQuery技術解密 (五)jQuery解密
- 第二章 jQuery技術解密 (六)jQuery解密
- 第二章 jQuery技術解密 (七)jQuery解密
- 《Web前端黑客技術解密》讀書筆記(第三、四、五章)Web前端黑客解密筆記
- 騰訊萬億級 Elasticsearch 技術解密Elasticsearch解密
- ChatGPT軟體技術棧解密ChatGPT解密
- Oracle Flashback 技術大解密Oracle解密
- 精通struts技術第二章(4) (轉)
- 精通struts技術第二章(5) (轉)
- 解密數倉的SQL ON ANYWHERE技術解密SQL
- 社交軟體紅包技術解密(十二):解密抖音春節紅包背後的技術設計與實踐解密
- 有獎書評活動:《京東技術解密》解密
- 第二章投資技術《第五節 背離》
- 讀《JavaScript核心技術開發解密》筆記JavaScript解密筆記
- 解密阿里巴巴安全技術體系解密阿里
- 【技術解密】SequoiaDB分散式儲存原理解密分散式
- [解密] DNA儲存技術究竟牛在哪裡?解密
- [原創]京東技術解密讀書筆記解密筆記
- jQuery第二章知識點jQuery
- jQuery第二章選擇器jQuery
- 讀《圖解密碼技術》(三):金鑰、隨機數和應用技術圖解解密密碼隨機
- 第二章投資技術《第三節 K線秘籍》
- vivo營銷自動化技術解密|開篇解密
- 解密|一文帶你看懂外掛技術解密
- jQuery第二章課後作業jQuery
- 技術境界的二三四
- 四、備份容災技術
- 技術問答集錦(四)
- 地球上最大的PHP站點後端技術解密PHP後端解密
- 解密阿里巴巴的技術發展路徑解密阿里
- 防禦網路威脅UTM技術解密(圖示)解密
- Elasticsearch核心技術(四):索引原理分析Elasticsearch索引
- 四種會話追蹤技術會話
- 區塊鏈技術筆記四區塊鏈筆記
- “聲討”高雲的《jQuery技術內幕》jQuery