jQuery源码解析之clone()

栏目: jQuery · 发布时间: 5年前

内容简介:前言:这篇讲完后,jQuery的二、

jQuery源码解析之clone()

前言:这篇讲完后,jQuery的 文档处理 就告一段落了,有空我把这部分整合下,发一篇文章目录。

一、示例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>jQuery源码解析之clone()</title>
</head>
<body>
<script src="jQuery.js"></script>

<div id="divTwo">
  <p id="pTwo">这是divTwo
    <span id="spanTwo">这是spanTwo</span>
  </p>
</div>
<div id="divOne">

</div>

<script>
  $("#pTwo").click(function () {
    alert("pTwo被点击了")
  })
  $("#spanTwo").click(function (e) {
    //阻止冒泡
    e.stopPropagation()
    alert("spanTwo被点击了")
  })
  // $("#pTwo").clone().appendTo($("#divOne"))
  // $("#pTwo").clone(true,false).appendTo($("#divOne"))
  $("#pTwo").clone(true,true).appendTo($("#divOne"))
</script>
</body>
</html>

二、 $() .clone()

作用:

生成被选元素的副本,包含子节点、文本和属性

注意:

$('div') .clone( true ) 表示克隆目标节点的 事件和数据

$('div') .clone( true,true ) 表示克隆目标节点及其子节点的 事件和数据

源码:

jQuery.fn.extend({
    //克隆目标节点及其子节点
    //dataAndEvents是否克隆目标节点的事件和数据,默认是false
    //deepDataAndEvents是否克隆目标节点子节点的事件和数据,默认值是dataAndEvents
    //源码6327行
    clone: function( dataAndEvents, deepDataAndEvents ) {
      //默认是false
      dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
      //默认是dataAndEvents
      deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
      //循环调用jQuery.clone
      return this.map( function() {
        return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
      } );
    },
});

解析:

可以看到,这里还是比较简单的,需要注意的就是 参数deepDataAndEvents 不填的话,其值是根据 参数dataAndEvents 的值来定的

三、jQuery.clone()

作用同上

源码:

jQuery.extend( {
    //源码6117行
    //生成被选元素的副本,包含子节点、文本和属性
    clone: function( elem, dataAndEvents, deepDataAndEvents ) {
      var i, l, srcElements, destElements,
        //拷贝目标节点的属性和值
        //如果为true,则包括拷贝子节点的所有属性和值
        clone = elem.cloneNode( true ),
        //判断elem是否脱离文档流
        inPage = jQuery.contains( elem.ownerDocument, elem );

      // Fix IE cloning issues
      //兼容性处理,解决IE bug
      if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
        !jQuery.isXMLDoc( elem ) ) {

        // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
        destElements = getAll( clone );
        srcElements = getAll( elem );

        for ( i = 0, l = srcElements.length; i < l; i++ ) {
          fixInput( srcElements[ i ], destElements[ i ] );
        }
      }

      // Copy the events from the original to the clone
      //从目标节点克隆事件,并绑定给克隆的元素
      if ( dataAndEvents ) {
        //克隆子节点的事件和数据
        if ( deepDataAndEvents ) {
          //源节点
          srcElements = srcElements || getAll( elem );
          //克隆节点
          destElements = destElements || getAll( clone );

          for ( i = 0, l = srcElements.length; i < l; i++ ) {
            cloneCopyEvent( srcElements[ i ], destElements[ i ] );
          }
        }
        //只克隆目标节点和数据
        else {
          cloneCopyEvent( elem, clone );
        }
      }

      //将script标签设为已运行
      // Preserve script evaluation history
      destElements = getAll( clone, "script" );
      if ( destElements.length > 0 ) {
        setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
      }

      // Return the cloned set
      return clone;
    },
})

解析:

可以看到这部分源码主要分为三大块:

(1)解决 IE 的 bug,主要是在 fixInput() 方法上进行处理

(2)从目标节点克隆数据、添加事件给克隆的元素

(3)将克隆的元素中的script标签设为已运行

四、fixInput()

作用:

(1)解决 IE 无法保存克隆的单选、多选的状态的 bug

(2)解决 IE 无法将克隆的选项返回至默认选项状态的 bug

源码:

//解决IE的bug:(1)无法保存克隆的单选、多选的状态 (2)无法将克隆的选项返回至默认选项状态
  // Fix IE bugs, see support tests
  //源码5937行
  function fixInput( src, dest ) {
    var nodeName = dest.nodeName.toLowerCase();

    // Fails to persist the checked state of a cloned checkbox or radio button.
    //IE无法保存克隆的单选框和多选框的选择状态
    if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
      dest.checked = src.checked;
    }
    //IE无法将克隆的选项返回至默认选项状态
    // Fails to return the selected option to the default selected state when cloning options
    else if ( nodeName === "input" || nodeName === "textarea" ) {
      dest.defaultValue = src.defaultValue;
    }
  }

解析:

本质就是将目标元素的 checked属性defaultValue属性 手动赋值给克隆的元素。

五、cloneCopyEvent()

作用:

$().clone() 的关键方法,用来从目标节点克隆数据、添加事件给克隆的元素

注意:

jQuery 采用数据分离的方法来保存 DOM 上的事件和数据,利用 uuid 标记每个 DOM 元素,然后在内存上,将每个 DOM 元素相关的数据放到内存中,然后在 uuid 和内存的数据之间建立映射。

优点是方便复制数据。

注意:事件是不可赋值的,只能一个个添加!

示意图:

jQuery源码解析之clone()

源码:

//src:目标元素
  //dest:克隆的元素
  //源码5902行
  function cloneCopyEvent( src, dest ) {
    var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;

    if ( dest.nodeType !== 1 ) {
      return;
    }
    //拷贝jQuery内部数据:事件、处理程序等
    // 1. Copy private data: events, handlers, etc.
    if ( dataPriv.hasData( src ) ) {
      //private data old,即目标元素的数据
      //注意:jQuery是通过uuid将目标元素进行标记,
      //然后将与目标元素相关的数据都放到内存中
      //通过uuid和内存的数据建立映射
      //这种数据分离的做法有利于复制数据,但不能复制事件
      pdataOld = dataPriv.access( src );
      //private data current,即为克隆的元素设置数据
      pdataCur = dataPriv.set( dest, pdataOld );
      events = pdataOld.events;
      //如果事件存在
      if ( events ) {
        //移除克隆对的元素的处理程序和事件
        delete pdataCur.handle;
        pdataCur.events = {};
        //依次为克隆的元素添加事件
        //注意:事件是不能被复制的,所以需要重新绑定
        for ( type in events ) {
          for ( i = 0, l = events[ type ].length; i < l; i++ ) {
            jQuery.event.add( dest, type, events[ type ][ i ] );
          }
        }
      }
    }

    // 2. Copy user data
    //拷贝用户数据
    if ( dataUser.hasData( src ) ) {
      udataOld = dataUser.access( src );
      udataCur = jQuery.extend( {}, udataOld );
      //为克隆的元素设置数据
      dataUser.set( dest, udataCur );
    }
  }

解析:

(1)拷贝 jQuery 内部数据(事件、处理程序)

拷贝赋值数据:

pdataOld = dataPriv.access( src );
//private data current,即为克隆的元素设置数据
pdataCur = dataPriv.set( dest, pdataOld );

拷贝添加事件:

jQuery.event.add( dest, type, events[ type ][ i ] );

(2)拷贝用户数据

dataUser.set( dest, udataCur );

六、setGlobalEval()

作用:

设置目标元素内部的 <script> 标签为已执行

源码:

//设置目标元素内部的`<script>`标签为已执行
  //源码4934行
  // Mark scripts as having already been evaluated
  function setGlobalEval( elems, refElements ) {
    var i = 0,
      l = elems.length;

    for ( ; i < l; i++ ) {
      dataPriv.set(
        elems[ i ],
        "globalEval",
        !refElements || dataPriv.get( refElements[ i ], "globalEval" )
      );
    }
  }

jQuery源码解析之clone()

(完)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Understanding Machine Learning

Understanding Machine Learning

Shai Shalev-Shwartz、Shai Ben-David / Cambridge University Press / 2014 / USD 48.51

Machine learning is one of the fastest growing areas of computer science, with far-reaching applications. The aim of this textbook is to introduce machine learning, and the algorithmic paradigms it of......一起来看看 《Understanding Machine Learning》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换