Quand les nœuds clonés sont-ils utilisés ?
Nous savons que si les nœuds sont utilisés directement lors des opérations DOM, les nœuds changeront avec l'opération. Par exemple, après avoir utilisé .after/.before/.append et d'autres méthodes sur un nœud, le nœud est ajouté à un nouvel emplacement et le nœud à l'emplacement d'origine est supprimé. Parfois, il est nécessaire de conserver le nœud à son emplacement d'origine et il suffit d'en ajouter une copie à l'emplacement correspondant. Dans ce cas, le clonage a un cas d'utilisation.
jQuery.fn.clone clone une copie de l'ensemble actuel d'éléments correspondants et la renvoie en tant qu'objet jQuery.
Vous pouvez également spécifier s'il faut copier des données supplémentaires (fonction data()) et des événements liés de ces éléments correspondants (même leurs enfants).
jQueyr.fn.clone : description du paramètre function(withDataAndEvents, deepDataAndEvents)
a. Les étapes d'implémentation sous-jacentes de la fonction clone se décomposent comme suit (jQuery.clone)
La première étape consiste à cloner le nœud DOM. Utilisez cloneNode(true) directement pour les nœuds DOM qui prennent en charge le clonage de nœud correct (c'est-à-dire prendre en charge elem.cloneNode et garantir un clonage correct), sinon créez un nœud pour enregistrer les données clonées, puis obtenez le nœud.
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 ); }
Dans la deuxième étape, si vous utilisez le navigateur IE, vous devez résoudre les problèmes de clonage d'IE un par un via fixCloneNodeIssues( node, destElements[i] );. Toutes les solutions de clonage IE sont incluses dans fixCloneNodeIssues, qui sera analysé en détail dans la section suivante. Cliquez ici pour voir plus de contenu jQuery.support
//针对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] ); } } }
La troisième étape, si vous souhaitez cloner les données du cache (y compris les données ordinaires et les événements de liaison), clonez-les.
//克隆绑定的事件 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 ); } }
Remarque : la fonction cloneCopyEvent enregistrera les données du nœud d'origine sur le nœud clone, puis liera les événements du nœud d'origine au nouveau nœud clone
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 ); } }
La quatrième étape consiste à protéger l'historique de calcul du script (marquer globalement le segment de code du script comme ayant été exécuté), à récupérer de la mémoire et à revenir au nœud de clonage.
destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } destElements = srcElements = node = null; return clone;
b.Résumé des problèmes de clonage d'IE fixCloneNodeIssues(src,dest)
src est le nœud d'origine et dest est le nœud clone de src.
Lister les problèmes de clonage d'IE (IE8)
1.IE6-8 clonera les événements lors de l'utilisation de cloneNode (ces événements sont liés via attachEvent). Afin de garantir l'uniformité, il est nécessaire d'effacer les événements clonés et de préparer les événements de clonage unifié ultérieurs
// 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-Lors du clonage du script de balise de script, le contenu cloné sera vide. Nous devons le réaffecter et nous assurer qu'il n'exécute pas le contenu du script.
//IE克隆脚本时内容为空白,并试图执行新设置的文本 if ( nodeName === "script" && dest.text !== src.text ) { disableScript( dest ).text = src.text; restoreScript( dest ); }
3.IE6-10 ne peut pas cloner les nœuds enfants de l'élément objet obtenu à l'aide du classid. Sous IE10, si le nœud parent est nul, une exception NoModificationAllowedError sera levée. Il est nécessaire de réattribuer le externalHTML et le innerHTML du nœud d'origine.
//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 ne peut pas cloner l'état sélectionné d'une case à cocher ou d'un bouton radio. Nécessite un paramètre actif.
// 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. Lors du clonage de la balise select, IE6-8 ne peut pas revenir correctement à l'état sélectionné par défaut. Nécessite un paramètre actif.
//当克隆选项时,IE6-8无法正确返回select默认选中状态 else if ( nodeName === "option" ) { dest.defaultSelected = dest.selected = src.defaultSelected; }
6. Lors du clonage d'autres types de balises input et textare, IE6-8 ne peut pas définir correctement defaultValue sur la valeur correcte. Nécessite un paramètre actif.
//当克隆其他类型的input标签时,IE6-8不能正确设置defaultValue为正确的值 else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; }
La fonction DisableScript est utilisée à l'intérieur. Le but de la fonction est de changer le type du script pour garantir qu'il ne sera pas exécuté en tant que script après avoir attribué une valeur au script. Nous pouvons apprendre de cette approche
//为安全DOM操作替换/保存script节点元素type属性 function disableScript( elem ) { var attr = elem.getAttributeNode("type"); elem.type = ( attr && attr.specified ) + "/" + elem.type; return elem; }
Le contenu ci-dessus est la description complète de la série d'analyses de code source jQuery-1.9.1 (11) Suite de l'opération DOM des nœuds de clonage introduite par l'éditeur. J'espère que vous l'aimerez.