DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> jQuery入門知識 >> JQuery特效代碼 >> jQuery.clean使用方法及思路分析
jQuery.clean使用方法及思路分析
編輯:JQuery特效代碼     

一、jQuery.clean使用方法
jQuery.clean( elems, context, fragment, scripts );
二、思路分析
1、處理參數context,確保其為文檔根節點document
2、處理參數elems數組(循環遍歷數組)
  2.1、elem為數字,轉換為字符串
  2.2、elem為非法值,跳出本次循環
  2.3、elem為字符串
  2.4、字符串不存在實體編號或html標簽,則創建文本節點
  2.5、字符串為實體編號或html標簽
. 代碼如下:
創建一個div元素並插入到文檔碎片中
處理xhtml風格標簽
將elem包裹起來,並將包裹後的字符串作為div的innerHTML
如果包裹深度大於1,只留下第一層包裹元素
清除在ie6,7中空table標簽自動加入的tbody
將在ie9以下浏覽器中剔除的開頭空白字符串作為div元素的第一個文本子節點
將elem重新賦值為div的子節點集合(nodeList對象),
移除本次循環中文檔碎片中的div,保持下一次循環中干淨的div元素    

2.3、如果elem為文本節點,則直接添加到要返回的ret數組中,否則將elem(nodeList對象)中的節點合並到數組
  2.4、修復在ie6、7中type為radio,checkbox類型的節點的選中狀態(checked)失效的bug
3、處理參數fragment
  3.1、將ret中各節點添加到文檔碎片fragment中
  3.2、提取節點中的script子節點,並將其添加到ret數組中,添加的script位置為其原父元素位置後面
4、返回ret數組
三、源碼注釋分析
1、函數中用到的變量及函數
. 代碼如下:
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
area: [ 1, "<map>", "</map>" ],
_default: [ 0, "", "" ]
},
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
rhtml = /<|&#?\w+;/,
rleadingWhitespace = /^\s+/,
rcheckableType = /^(?:checkbox|radio)$/,
rscriptType = /\/(java|ecma)script/i;
// 設置復選框checkbox或單選框radio表單元素的默認選中狀態
function fixDefaultChecked( elem ) {
if ( rcheckableType.test( elem.type ) ) {
elem.defaultChecked = elem.checked;
}
}
// 創建一個安全的文檔碎片
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment(); // ie6,7,8浏覽器把safeFrage作為HTMLDocument類型
// 針對ie9以下浏覽器
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
// 模擬ES5中Array的新功能
// 該函數API:http://www.css88.com/jqapi-1.8/#p=jQuery.grep
jQuery.extend({
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
}
});

2、源碼分析
. 代碼如下:
jQuery.extend({
clean: function( elems, context, fragment, scripts ) {
// 聲明變量
var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
safe = context === document && safeFragment,
ret = [];
// 確保變量context為文檔根節點document
if ( !context || typeof context.createDocumentFragment === "undefined" ) {
context = document;
}
// Use the already-created safe fragment if context permits
for ( i = 0; (elem = elems[i]) != null; i++ ) {
// 如果elem為數字,則將其轉換為字符串
if ( typeof elem === "number" ) {
elem += "";
}
// 如果elem為undefined,跳出本次循環
if ( !elem ) {
continue;
}
// Convert html string into DOM nodes
// 轉換數組項(字符串)為DOM節點
if ( typeof elem === "string" ) {
// 如果不存在html實體編號或標簽,則創建文本節點
if ( !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
}
// 處理是html標簽字符串的數組項
else {
// Ensure a safe container in which to render the html
// safe為#document-fragment類型,在ie9以下浏覽器中,safe為HTMLDocument類型節點,且nodeNames數組為空
safe = safe || createSafeFragment( context );
// 創建一個div元素並將其插入到文檔碎片中
div = context.createElement("div");
safe.appendChild( div );
// Fix "XHTML"-style tags in all browsers
// 除了area,br,col,embed,hr,img,input,link,meta,param這些標簽外,
// 將開始標簽末尾加入斜槓的標簽轉換為開始和結束標簽
elem = elem.replace(rxhtmlTag, "<$1></$2>");
// Go to html and back, then peel off extra wrappers
// 獲取左邊第一個標簽元素
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
// 獲取最外層元素的包裹元素,並將元素包裹在其中
wrap = wrapMap[ tag ] || wrapMap._default;
depth = wrap[0];
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
// 如果元素的包裹深度大於1,div重新賦值為元素最近的包裹元素(即:包含第一層包裹元素)
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted <tbody> from table fragments
// 在IE6,7中,清除字符串中空table標簽中自動加入的tbody標簽(手動加入的除外)
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious(偽造的) <tbody>
// 判斷字符串中是否擁有空tbody標簽
hasBody = rtbody.test(elem);
// 如果最外層標簽為table且table中沒有手動加入tbody
// 變量tbody為div.firstChild.childNodes(自動加入的tbody標簽集合)
tbody = tag === "table" && !hasBody ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
// 如果字符串中僅有一個空thead或tfoot標簽
// 變量tbody為div.childNodes(字符串中的thead和tfoot標簽集合)
wrap[1] === "<table>" && !hasBody ?
div.childNodes :
[];
for ( j = tbody.length - 1; j >= 0 ; --j ) {
// 排除thead或tfoot標簽
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
// 清除空table標簽中自動加入的tbody
tbody[ j ].parentNode.removeChild( tbody[ j ] );
}
}
}
// IE completely kills leading whitespace when innerHTML is used
// 在ie9以下浏覽器中,字符串以空白字符串開頭,將空白字符串作為div元素的第一個文本子節點
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
}
// 獲取已經處理完畢的div子節點集合(nodeList對象)
elem = div.childNodes;
// Take out of fragment container (we need a fresh div each time)
// 在下一次循環處理字符串數組項前,清除處理創建過的div元素
div.parentNode.removeChild( div );
}
}
// 如果elem為DOM節點(文本節點)
if ( elem.nodeType ) {
ret.push( elem );
}
// 將nodeList對象中節點合並到返回的數組中
else {
jQuery.merge( ret, elem );
}
}
// Fix #11356: Clear elements from safeFragment
if ( div ) {
elem = div = safe = null;
}
// Reset defaultChecked for any radios and checkboxes
// about to be appended to the DOM in IE 6/7 (#8060)
// 在ie6,7中,擁有checked屬性的單選按鈕,復選框在插入到其他標簽後,選中狀態會失效(下面代碼修復該bug)
if ( !jQuery.support.appendChecked ) {
for ( i = 0; (elem = ret[i]) != null; i++ ) {
if ( jQuery.nodeName( elem, "input" ) ) {
fixDefaultChecked( elem );
} else if ( typeof elem.getElementsByTagName !== "undefined" ) {
jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
}
}
}
// Append elements to a provided document fragment
// 將ret數組中的各DOM節點插入到提供的文檔碎片中
// 提取dom節點中的script節點,並添加到ret數組中,位置為其原父元素索引位置後
if ( fragment ) {
// Special handling of each script element
handleScript = function( elem ) {
// Check if we consider it executable
// 如果elem元素不存在type屬性或者type值為javascript或者為ecmascript
if ( !elem.type || rscriptType.test( elem.type ) ) {
// Detach the script and store it in the scripts array (if provided) or the fragment
// Return truthy to indicate that it has been handled
return scripts ?
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
fragment.appendChild( elem );
}
};
for ( i = 0; (elem = ret[i]) != null; i++ ) {
// Check if we're done after handling an executable script
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
// Append to fragment and handle embedded scripts
// 將elem元素添加到文檔碎片中並處理嵌入的腳本(script標簽元素)
fragment.appendChild( elem );
if ( typeof elem.getElementsByTagName !== "undefined" ) {
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
// Splice the scripts into ret after their former ancestor and advance our index beyond them
// 將script標簽添加到數組,位置為其原父元素索引位置後
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
i += jsTags.length;
}
}
}
}
return ret;
}
});

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved