jQuery Source Parsing DOM Operation Module Replication Element Details

Keywords: Javascript JQuery html5 IE Attribute

This section describes the replication element sub-module in the DOM operation module, which replicates a DOM node and optionally sets whether to replicate its data cache objects (including event information) and whether to replicate in depth (descendant nodes, etc.), with the following API s:

  • $.clone(elem, dataAndEvents, deepDataAndEvents); jQuery underlying method, returning DOM reference; elem is the DOM element to be copied; dataAndEvents and deepDataAndEvents indicate whether to copy cloned element data and events, respectively; and whether to copy deep replication data and events.
  • $.fn.clone(dataAndEvents,deepDataAndEvents); jQuery instance method, returns a jQuery object; parameter 2 equals parameter 1 if parameter 1 is specified and parameter 2 is empty

writer by:Desert QQ:22969969

Or raise a chestnut first:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    <div style="width: 150px;height: 50px;background: #cfc;">
        <p>The weather is nice today</p>
    <button id="b1">Button 1</button>
    <button id="b2">Button 2</button>
    <button id="b3">Button 3</button>
    <button id="b4">Button 4</button>

        $('div').click(function(){console.log('div click');})                     //to div Bind one click Event
        $('p').click(function(){console.log('p click');})                         //to p Bind one click Event

        /*Clicking on Button 1, Button 2, Button 3, Button 4 will copy the div and add it to the end of the body, then clicking on the p element in the copied block will output as follows:*/
        $('#b1').click(function(){$('div').clone().appendTo('body');})            //No output
        $('#b2').click(function(){$('div').clone(true,false).appendTo('body');})  //output:clone_d1 click
        $('#b3').click(function(){$('div').clone(true,true).appendTo('body');})   //output:clone_p1 click,clone_d1 click
        $('#b4').click(function(){$('div').clone(true).appendTo('body');})        //output:clone_p1 click,clone_d1 click  ;Because parameter 2 is omitted, it defaults to parameter 1

Render as follows:

We have two events bound on div and p, respectively. Click on the P element (the text for today's fine weather) console and output as follows:

In addition, any button we click will clone the div element, rendering as follows:

Simply click on the p element of the cloned element, that is, the text the arrow clicks, and the console output will be different, for the four buttons, as follows:

  • Button 1; No Output > clone() does not pass in parameters, so data cache objects will not be copied
  • Button 2; Output: One line: div click; clone() passes in true and false, so only one copy of the div's data cache object will be made, not p
  • Button 3; Output two lines: p click and div click; clone() passes in two true, making a deep copy, and the data objects of the descendant nodes are copied over
  • Button 4; Output two lines: p click and div click; Clone () passes in only one true, the same as Button 3, and see the code analysis below


Source Code Analysis

Start with $.clone(), which is jQuery's underlying method, as follows:

    clone: function( elem, dataAndEvents, deepDataAndEvents ) {         //copy DOM Element, and fix incompatible attributes. dataAndEvents:Whether to copy data and events. deepDataAndEvents:Whether to copy data and events of descendant elements.
        var srcElements,
            // IE<=8 does not properly clone detached, unknown element nodes
            clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?    //If browser supports HTML5 Element, or not supported html5 And the original element does not contain html5 element 
                elem.cloneNode( true ) :                                                            //Call Native Method.clone(deep)copy DOM element 
                shimCloneNode( elem );                                                              //Otherwise, call the function shimCloneNode()adopt"Secure Document Fragments"copy HTML5 element

        if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&                //Correct Incompatibility
                (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
            // IE copies events bound via attachEvent when using cloneNode.
            // Calling detachEvent on the clone will also remove the events
            // from the original. In order to get around this, we use some
            // proprietary methods to clear the events. Thanks to MooTools
            // guys for this hotness.

            cloneFixAttributes( elem, clone );

            // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
            srcElements = getAll( elem );
            destElements = getAll( clone );

            // Weird iteration because IE will replace the length property
            // with an element if you are cloning the body and one of the
            // elements on the page has a name or id of "length"
            for ( i = 0; srcElements[i]; ++i ) {
                // Ensure that the destination node is not null; Fixes #9587
                if ( destElements[i] ) {
                    cloneFixAttributes( srcElements[i], destElements[i] );

        // Copy the events from the original to the clone
        if ( dataAndEvents ) {                      //If data and events are copied
            cloneCopyEvent( elem, clone );              //call cloneCopyEvent()data

            if ( deepDataAndEvents ) {                  //If it is deep copy
                srcElements = getAll( elem );               //Get Source DOM Node All Child Nodes DOM Quote
                destElements = getAll( clone );             //Get Goals DOM Node All Child Nodes DOM Quote

                for ( i = 0; srcElements[i]; ++i ) {        //Traversing Sources DOM Child nodes of a node
                    cloneCopyEvent( srcElements[i], destElements[i] );  //Copy data caches one by one

        srcElements = destElements = null;

        // Return the cloned set
        return clone;                               //Last Return clone,That is, copied out DOM element

$.clone() calls the native cloneNode() method to copy a DOM, and cloneCopyEvent() copies the data cache as follows:

function cloneCopyEvent( src, dest ) {      //Copy data and events   ;$.clone()function call  ;src Is Source DOM Node, dest Is Target Node

    if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {  //If dest Not an element node or src Return without data

    var type, i, l,
        oldData = jQuery._data( src ),                      //Get the internal data of the original object
        curData = jQuery._data( dest, oldData ),            //Set the internal data of the target object   ;At this time src and dest Event objects within two objects(events and handle attribute)All point to the same
        events = oldData.events;                            //Event object of original object

    if ( events ) {                                         //If Source DOM If the object has a bound event handler, delete the target DOM Event information for the object, then rebind
        delete curData.handle;                                  //Delete the listening handle of the target object
        curData.events = {};                                    //Reset the list of events for the target object

        for ( type in events ) {                                //Traversing Sources DOM Event List of Objects
            for ( i = 0, l = events[ type ].length; i < l; i++ ) {  //Traverse through each of the bound functions
                jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );   //Target in turn DOM Bind event operations on objects

    // make the cloned public data object a copy from the original
    if ( curData.data ) {                                   //If Source DOM Object Contains Custom Event Object
        curData.data = jQuery.extend( {}, curData.data );       //Also make a separate copy and save it to curData.data in

As you can see from the source code, if an event object is bound, jQuery.event.add() is called to bind in turn, which is what happens.

For the instance method $.fn.clone(), its implementation is as follows:

    clone: function( dataAndEvents, deepDataAndEvents ) {           //Create a deep copy of the set of matching elements. dataAndEvents:Optional Boolean value indicating whether to copy data and events, defaulting to false. deepDataAndEvents:An optional Boolean value indicating whether to copy data and events in depth, defaulting to false. 
        dataAndEvents = dataAndEvents == null ? false : dataAndEvents;                      //correct dataAndEvents parameter
        deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;  //correct deepDataAndEvents parameter

        return this.map( function () {                                      //Call that hair.map()Traverse through the set of matching elements, called in callback function jQuery.clone()Copy each matching element.
            return jQuery.clone( this, dataAndEvents, deepDataAndEvents );      //Call underlying jQuery.clone()Method

As you can see here, for $.fn.clone(), if parameter 2 is not passed, then parameter 1 will be corrected, and button 4 in the example above is executed here.

Posted by Vince on Sun, 10 Nov 2019 17:42:17 -0800