Home  >  Article  >  Web Front-end  >  jQuery-1.9.1 Source Code Analysis Series (11) DOM Operations Continued Cloning Nodes_jquery

jQuery-1.9.1 Source Code Analysis Series (11) DOM Operations Continued Cloning Nodes_jquery

WBOY
WBOYOriginal
2016-05-16 15:28:321289browse

When are cloned nodes used?

We know that if nodes are used directly during DOM operations, nodes will change with the operation. For example, after using .after/.before/.append and other methods on a node, the node is added to a new location and the node at the original location is removed. Sometimes it is necessary to retain the node at its original location and only need to add a copy to the corresponding location. In this case, cloning has a use case.

jQuery.fn.clone clones a copy of the current set of matching elements and returns it as a jQuery object.

You can also specify whether to copy additional data (data() function) and bound events of these matching elements (even their children).

jQueyr.fn.clone: ​​function(withDataAndEvents, deepDataAndEvents) parameter description

a. The underlying implementation steps of the clone function are broken down as follows (jQuery.clone)

The first step is to clone the DOM node. Use cloneNode(true) directly for DOM nodes that support correct node cloning (that is, support elem.cloneNode and ensure correct cloning), otherwise build a node to save the cloned data and then obtain the node.

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 );
}

In the second step, if you are using IE browser, you need to fix IE cloning issues one by one through fixCloneNodeIssues( node, destElements[i] );. All IE cloning solutions are included in fixCloneNodeIssues, which will be analyzed in detail in the next section. Click here to view more jQuery.support content

//针对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] );
    }
  }
}

The third step, if you want to clone the cache data (including ordinary data and binding events), clone it.

//克隆绑定的事件
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 );
  }
}

Note: The cloneCopyEvent function will save the data of the original node to the clone node, and then bind the events of the original node to the new clone node

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 );
    }
  }

The fourth step is to protect the script calculation history (globally mark the scripts code segment as having been executed), reclaim memory, and return to the clone node.

destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
  setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
destElements = srcElements = node = null;
return clone;

b. Summary of IE cloning issues fixCloneNodeIssues(src,dest)

src is the original node, and dest is the clone node of src.

List the IE cloning problems (IE8)

1.IE6-8 will clone events when using cloneNode (these events are bound through attachEvent). In order to ensure uniformity, it is necessary to clear the cloned events and prepare for subsequent unified cloning events

  // 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-When cloning the script tag script, the cloned content will be blank. We need to reassign it and ensure that it does not execute the script content.

//IE克隆脚本时内容为空白,并试图执行新设置的文本
  if ( nodeName === "script" && dest.text !== src.text ) {
    disableScript( dest ).text = src.text;
    restoreScript( dest );
    }

 3.IE6-10 cannot clone the child nodes of the object element obtained using the classid. Under IE10, if the parent node is null, a NoModificationAllowedError exception will be thrown. It is necessary to reassign the outerHTML and innerHTML of the original node.

 //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 cannot clone the selected state of a check box or radio button. Requires active setting.

 // manipulation_rcheckableType = /^(&#63;:checkbox|radio)$/i
  else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
    //IE6-8无法坚持一个克隆的复选框或单选按钮的选中状态
    //更糟的是,如果defaultChecked值没有设置,则IE6-7无法给克隆元素选中状态的外观
    dest.defaultChecked = dest.checked = src.checked;
    ...
  }

5. When cloning the select tag, IE6-8 cannot correctly return to the select default selected state. Requires active setting.

   //当克隆选项时,IE6-8无法正确返回select默认选中状态
   else if ( nodeName === "option" ) {
    dest.defaultSelected = dest.selected = src.defaultSelected;
   }

6. When cloning other types of input and textare tags, IE6-8 cannot correctly set defaultValue to the correct value. Requires active setting.

  //当克隆其他类型的input标签时,IE6-8不能正确设置defaultValue为正确的值
  else if ( nodeName === "input" || nodeName === "textarea" ) {
    dest.defaultValue = src.defaultValue;
  }

The disableScript function is used inside. The purpose of the function is to change the type of the script to ensure that it will not be executed as a script after assigning a value to the script. We can learn from this approach

//为安全DOM操作替换/保存script节点元素type属性
function disableScript( elem ) {
  var attr = elem.getAttributeNode("type");
  elem.type = ( attr && attr.specified ) + "/" + elem.type;
  return elem;
}

The above content is the entire description of the jQuery-1.9.1 source code analysis series (11) DOM operation continuation of cloning nodes introduced by the editor. I hope you like it.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn