jQuery-1.9.1源碼分析系列(十一)DOM操作續(xù)之克隆節(jié)點
什么情況下使用到克隆節(jié)點?
我們知道在對DOM操作過程中如果直接使用節(jié)點會出現(xiàn)節(jié)點隨操作而變動的情況。比如對節(jié)點使用.after/.before/.append等方法后,節(jié)點被添加到新的地方,原來的位置上的節(jié)點被移除了。有的時候需要保留原來位置上的節(jié)點,僅僅是需要一個副本添加到對應(yīng)位置,這個時候克隆就有了使用場景。
jQuery.fn.clone克隆當前匹配元素集合的一個副本,并以jQuery對象的形式返回。
你還可以指定是否復(fù)制這些匹配元素(甚至它們的子元素)的附加數(shù)據(jù)( data()函數(shù) )和綁定事件。
jQueyr.fn.clone: function( withDataAndEvents, deepDataAndEvents )參數(shù)描述
a.克隆函數(shù)的底層實現(xiàn)步驟分解如下(jQuery.clone)
第一步,先克隆出DOM節(jié)點。對支持正確的節(jié)點克?。粗С謊lem.cloneNode并保證克隆無誤)的DOM節(jié)點直接使用cloneNode(true),否則自建一個節(jié)點來保存被克隆數(shù)據(jù)然后獲取該節(jié)點。
if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
clone = elem.cloneNode( true );
// IE<=8 不能正確克隆已分離、未知的節(jié)點
//直接新建一個相同的節(jié)點,然后獲取
} else {
//fragmentDiv是全局變量
fragmentDiv.innerHTML = elem.outerHTML;
fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
}
第二步,如果是IE瀏覽器下,則需要通過fixCloneNodeIssues( node, destElements[i] );來逐個修正IE克隆問題。IE克隆解決方案全部包含在了fixCloneNodeIssues中,下一節(jié)詳細分析。里面的jQuery.support內(nèi)容點擊這里查看更多
//針對ie克隆問題修正
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
//在這里我們不使用Sizzle的原因是: http://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone );
srcElements = getAll( elem );
//修正所有IE克隆問題
for ( i = 0; (node = srcElements[i]) != null; ++i ) {
// Ensure that the destination node is not null; Fixes #9587
if ( destElements[i] ) {
fixCloneNodeIssues( node, destElements[i] );
}
}
}
第三步,如果要克隆緩存數(shù)據(jù)(包括普通數(shù)據(jù)和綁定事件),克隆之。
//克隆綁定的事件
if ( dataAndEvents ) {
if ( deepDataAndEvents ) {
srcElements = srcElements || getAll( elem );
destElements = destElements || getAll( clone );
for ( i = 0; (node = srcElements[i]) != null; i++ ) {
cloneCopyEvent( node, destElements[i] );
}
} else {
cloneCopyEvent( elem, clone );
}
}
備注:cloneCopyEvent函數(shù)中會將原節(jié)點的數(shù)據(jù)保存到克隆節(jié)點中,然后將原節(jié)點的事件綁定到新的克隆節(jié)點上
function cloneCopyEvent( src, dest ) {
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
return;
}
var type, i, l,
oldData = jQuery._data( src ),
curData = jQuery._data( dest, oldData ),//dest是克隆對的節(jié)點
events = oldData.events;
if ( events ) {
//保證被克隆的節(jié)點的事件對象干凈,確保沒有后面添加的事件沒有重復(fù)
delete curData.handle;
curData.events = {};
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
// 使克隆的數(shù)據(jù)對象化
if ( curData.data ) {
curData.data = jQuery.extend( {}, curData.data );
}
}
第四步,保護script計算歷史(全局性地標記scripts代碼段已經(jīng)被執(zhí)行過了),并回收內(nèi)存,返回克隆節(jié)點。
destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
destElements = srcElements = node = null;
return clone;
b.IE克隆問題匯總fixCloneNodeIssues(src,dest)
src是原節(jié)點,dest是src的克隆節(jié)點。
IE克隆問題列一下(IE8+)
1.IE6-8當使用cloneNode會克隆事件(這些事件綁定通過attachEvent)。為保證統(tǒng)一性,需要清除克隆的事件,為后續(xù)統(tǒng)一克隆事件做準備
// IE6-8當使用cloneNode復(fù)制事件(這些事件綁定通過attachEvent)時進入該分支
//清除原來的事件,為克隆事件做準備
if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
data = jQuery._data( dest );
for ( e in data.events ) {
jQuery.removeEvent( dest, e, data.handle );
}
dest.removeAttribute( jQuery.expando );
}
2.IE8-克隆腳本標簽script的時候克隆的內(nèi)容結(jié)果會是空白。我們需要給他重新賦值,并確保他不會執(zhí)行腳本內(nèi)容。
//IE克隆腳本時內(nèi)容為空白,并試圖執(zhí)行新設(shè)置的文本
if ( nodeName === "script" && dest.text !== src.text ) {
disableScript( dest ).text = src.text;
restoreScript( dest );
}
3.IE6-10不能克隆使用的classid獲取的對象元素的子節(jié)點。IE10下,如果父節(jié)點為null,則會拋出NoModificationAllowedError異常。需要使用原節(jié)點的outerHTML和innerHTML重新賦值。
//IE6-10不能克隆使用的classid獲取的對象元素的子節(jié)點。
//IE10下,如果父節(jié)點為null,則會拋出NoModificationAllowedError異常
else if ( nodeName === "object" ) {
if ( dest.parentNode ) {
dest.outerHTML = src.outerHTML;
}
//對于IE9,這個條分支不可避免。
//IE9中克隆對象元素,上述outerHTML策略是不充分的。
//如果src具有的innerHTML并且克隆節(jié)點卻沒有,
//復(fù)制src.innerHTML到dest.innerHTML #10324
if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
dest.innerHTML = src.innerHTML;
}
}
4.IE6-8無法克隆一個復(fù)選框或單選按鈕的選中狀態(tài)。需要主動設(shè)置。
// manipulation_rcheckableType = /^(?:checkbox|radio)$/i
else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
//IE6-8無法堅持一個克隆的復(fù)選框或單選按鈕的選中狀態(tài)
//更糟的是,如果defaultChecked值沒有設(shè)置,則IE6-7無法給克隆元素選中狀態(tài)的外觀
dest.defaultChecked = dest.checked = src.checked;
...
}
5.當克隆select標簽時,IE6-8無法正確返回select默認選中狀態(tài)。需要主動設(shè)置。
//當克隆選項時,IE6-8無法正確返回select默認選中狀態(tài)
else if ( nodeName === "option" ) {
dest.defaultSelected = dest.selected = src.defaultSelected;
}
6.當克隆其他類型的input和textare標簽時,IE6-8不能正確設(shè)置defaultValue為正確的值。需要主動設(shè)置。
//當克隆其他類型的input標簽時,IE6-8不能正確設(shè)置defaultValue為正確的值
else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
}
里面用到disableScript這個函數(shù)。函數(shù)目的是改變script的type,從而保證在給script賦值后不會被作為腳本執(zhí)行。這個方式我們可以借鑒
//為安全DOM操作替換/保存script節(jié)點元素type屬性
function disableScript( elem ) {
var attr = elem.getAttributeNode("type");
elem.type = ( attr && attr.specified ) + "/" + elem.type;
return elem;
}
以上內(nèi)容是小編給大家介紹的關(guān)于jQuery-1.9.1源碼分析系列(十一)DOM操作續(xù)之克隆節(jié)點的全部敘述,希望大家喜歡。
- Android Tween動畫之RotateAnimation實現(xiàn)圖片不停旋轉(zhuǎn)效果實例介紹
- jQuery1.9.1針對checkbox的調(diào)整方法(prop)
- jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之綁定事件
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件體系結(jié)構(gòu)
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件包裝
- Jquery1.9.1源碼分析系列(六)延時對象應(yīng)用之jQuery.ready
- jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之主動觸發(fā)事件和模擬冒泡處理
- Jquery-1.9.1源碼分析系列(十一)之DOM操作
- Jquery 1.9.1源碼分析系列(十二)之篩選操作
- jQuery 1.9.1源碼分析系列(十三)之位置大小操作
- jQuery 1.9.1源碼分析系列(十四)之常用jQuery工具
- jQuery 1.9.1源碼分析系列(十五)動畫處理之緩動動畫核心Tween
相關(guān)文章
jQuery focus和blur事件的應(yīng)用詳解
本篇文章主要是對jQuery中focus和blur事件的應(yīng)用進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01
jQuery+ajax實現(xiàn)鼠標單擊修改內(nèi)容的思路
這篇文章主要介紹了jQuery+ajax實現(xiàn)鼠標單擊修改內(nèi)容的思路及核心代碼,需要的朋友可以參考下2014-06-06
基于jQuery 實現(xiàn)bootstrapValidator下的全局驗證
這篇文章主要介紹了基于jQuery 實現(xiàn)bootstrapValidator下的全局驗證 的相關(guān)資料,需要的朋友可以參考下2015-12-12
jQuery插件echarts實現(xiàn)的循環(huán)生成圖效果示例【附demo源碼下載】
這篇文章主要介紹了jQuery插件echarts實現(xiàn)的循環(huán)生成圖效果,結(jié)合完整實例形式分析了echarts插件循環(huán)輸出數(shù)字圖形的實現(xiàn)步驟與相關(guān)操作技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-03-03

