Wann werden geklonte Knoten verwendet?
Wir wissen, dass sich Knoten mit der Operation ändern, wenn Knoten direkt während DOM-Vorgängen verwendet werden. Nach der Verwendung von .after/.before/.append und anderen Methoden auf einem Knoten wird der Knoten beispielsweise an einem neuen Standort hinzugefügt und der Knoten am ursprünglichen Standort entfernt. Manchmal ist es notwendig, den Knoten an seinem ursprünglichen Speicherort beizubehalten und nur eine Kopie am entsprechenden Speicherort hinzuzufügen. In diesem Fall hat das Klonen einen Anwendungsfall.
jQuery.fn.clone klont eine Kopie des aktuellen Satzes übereinstimmender Elemente und gibt sie als jQuery-Objekt zurück.
Sie können auch angeben, ob zusätzliche Daten (Funktion data()) und gebundene Ereignisse dieser übereinstimmenden Elemente (sogar ihrer untergeordneten Elemente) kopiert werden sollen.
jQueyr.fn.clone: function(withDataAndEvents, deepDataAndEvents) Parameterbeschreibung
a. Die zugrunde liegenden Implementierungsschritte der Klonfunktion sind wie folgt unterteilt (jQuery.clone)
Der erste Schritt besteht darin, den DOM-Knoten zu klonen. Verwenden Sie cloneNode(true) direkt für DOM-Knoten, die das korrekte Klonen von Knoten unterstützen (d. h. elem.cloneNode unterstützen und das korrekte Klonen sicherstellen). Andernfalls erstellen Sie einen Knoten, um die geklonten Daten zu speichern, und rufen Sie dann den Knoten ab.
if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { clone = elem.cloneNode( true ); // IE<=8 不能正确克隆已分离、未知的节点 //直接新建一个相同的节点,然后获取 } else { //fragmentDiv是全局变量 fragmentDiv.innerHTML = elem.outerHTML; fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); }
Wenn Sie im zweiten Schritt einen IE-Browser verwenden, müssen Sie die IE-Klonprobleme einzeln über fixCloneNodeIssues( node, destElements[i] ); beheben. Alle IE-Klonlösungen sind in fixCloneNodeIssues enthalten, die im nächsten Abschnitt ausführlich analysiert werden. Klicken Sie hier, um weitere jQuery.support-Inhalte anzuzeigen
//针对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] ); } } }
Der dritte Schritt: Wenn Sie die Cache-Daten (einschließlich gewöhnlicher Daten und Bindungsereignisse) klonen möchten, klonen Sie sie.
//克隆绑定的事件 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 ); } }
Hinweis: Die cloneCopyEvent-Funktion speichert die Daten des ursprünglichen Knotens auf dem Klonknoten und bindet dann die Ereignisse des ursprünglichen Knotens an den neuen Klonknoten
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是克隆对的节点 events = oldData.events; if ( events ) { //保证被克隆的节点的事件对象干净,确保没有后面添加的事件没有重复 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 ] ); } } } // 使克隆的数据对象化 if ( curData.data ) { curData.data = jQuery.extend( {}, curData.data ); } }
Der vierte Schritt besteht darin, den Skriptberechnungsverlauf zu schützen (das Codesegment des Skripts global als ausgeführt zu markieren), Speicher freizugeben und zum Klonknoten zurückzukehren.
destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } destElements = srcElements = node = null; return clone;
b. Zusammenfassung der IE-Klonprobleme fixCloneNodeIssues(src,dest)
src ist der ursprüngliche Knoten und dest ist der Klonknoten von src.
Listen Sie die Probleme beim IE-Klonen auf (IE8)
1.IE6-8 klont Ereignisse, wenn cloneNode verwendet wird (diese Ereignisse werden durch attachmentEvent gebunden). Um die Einheitlichkeit sicherzustellen, ist es notwendig, die geklonten Ereignisse zu löschen und sich auf nachfolgende einheitliche Klonereignisse vorzubereiten
// IE6-8当使用cloneNode复制事件(这些事件绑定通过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-Beim Klonen des Skript-Tag-Skripts ist der geklonte Inhalt leer. Wir müssen es neu zuweisen und sicherstellen, dass der Skriptinhalt nicht ausgeführt wird.
//IE克隆脚本时内容为空白,并试图执行新设置的文本 if ( nodeName === "script" && dest.text !== src.text ) { disableScript( dest ).text = src.text; restoreScript( dest ); }
3.IE6-10 kann die untergeordneten Knoten des mithilfe der Klassen-ID erhaltenen Objektelements nicht klonen. Wenn der übergeordnete Knoten unter IE10 null ist, wird eine NoModificationAllowedError-Ausnahme ausgelöst. Es ist notwendig, das äußereHTML und das innereHTML des ursprünglichen Knotens neu zuzuweisen.
//IE6-10不能克隆使用的classid获取的对象元素的子节点。 //IE10下,如果父节点为null,则会抛出NoModificationAllowedError异常 else if ( nodeName === "object" ) { if ( dest.parentNode ) { dest.outerHTML = src.outerHTML; } //对于IE9,这个条分支不可避免。 //IE9中克隆对象元素,上述outerHTML策略是不充分的。 //如果src具有的innerHTML并且克隆节点却没有, //复制src.innerHTML到dest.innerHTML #10324 if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { dest.innerHTML = src.innerHTML; } }
4.IE6-8 kann den ausgewählten Status eines Kontrollkästchens oder Optionsfelds nicht klonen. Erfordert aktive Einstellung.
// manipulation_rcheckableType = /^(?:checkbox|radio)$/i else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { //IE6-8无法坚持一个克隆的复选框或单选按钮的选中状态 //更糟的是,如果defaultChecked值没有设置,则IE6-7无法给克隆元素选中状态的外观 dest.defaultChecked = dest.checked = src.checked; ... }
5. Beim Klonen des Select-Tags kann IE6-8 nicht korrekt zum Select-Standard-Select-Status zurückkehren. Erfordert aktive Einstellung.
//当克隆选项时,IE6-8无法正确返回select默认选中状态 else if ( nodeName === "option" ) { dest.defaultSelected = dest.selected = src.defaultSelected; }
6. Beim Klonen anderer Arten von Eingabe- und Textare-Tags kann IE6-8 defaultValue nicht korrekt auf den richtigen Wert setzen. Erfordert aktive Einstellung.
//当克隆其他类型的input标签时,IE6-8不能正确设置defaultValue为正确的值 else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; }
Im Inneren wird die Funktion „disableScript“ verwendet. Der Zweck der Funktion besteht darin, den Typ des Skripts zu ändern, um sicherzustellen, dass es nicht als Skript ausgeführt wird, nachdem dem Skript ein Wert zugewiesen wurde. Aus diesem Ansatz können wir lernen
//为安全DOM操作替换/保存script节点元素type属性 function disableScript( elem ) { var attr = elem.getAttributeNode("type"); elem.type = ( attr && attr.specified ) + "/" + elem.type; return elem; }
Der obige Inhalt ist die gesamte Beschreibung der vom Herausgeber eingeführten jQuery-1.9.1-Quellcode-Analysereihe (11). DOM-Operation Fortsetzung des Klonens von Knoten.