资讯专栏INFORMATION COLUMN

jQuery源码解析之clone()

coolpail / 1570人阅读

摘要:五作用的关键方法,用来从目标节点克隆数据添加事件给克隆的元素注意采用数据分离的方法来保存上的事件和数据,利用标记每个元素,然后在内存上,将每个元素相关的数据放到内存中,然后在和内存的数据之间建立映射。

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

一、示例代码

  1. jQuery源码解析之<span class="hljs-built_in">clone</span>()
  2. 这是divTwo

  3. 这是spanTwo
  4. 这是divTwo

  5. 这是spanTwo
  6. 这是divTwo

  7. 这是spanTwo

二、$().clone()
作用:
生成被选元素的副本,包含子节点、文本和属性

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

源码:

</>code

  1. jQuery.fn.extend({
  2. //克隆目标节点及其子节点
  3. //dataAndEvents是否克隆目标节点的事件和数据,默认是false
  4. //deepDataAndEvents是否克隆目标节点子节点的事件和数据,默认值是dataAndEvents
  5. //源码6327行
  6. clone: function( dataAndEvents, deepDataAndEvents ) {
  7. //默认是false
  8. dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  9. //默认是dataAndEvents
  10. deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  11. //循环调用jQuery.clone
  12. return this.map( function() {
  13. return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  14. } );
  15. },
  16. });

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

三、jQuery.clone()
作用同上

源码:

</>code

  1. jQuery.extend( {
  2. //源码6117行
  3. //生成被选元素的副本,包含子节点、文本和属性
  4. clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  5. var i, l, srcElements, destElements,
  6. //拷贝目标节点的属性和值
  7. //如果为true,则包括拷贝子节点的所有属性和值
  8. clone = elem.cloneNode( true ),
  9. //判断elem是否脱离文档流
  10. inPage = jQuery.contains( elem.ownerDocument, elem );
  11. // Fix IE cloning issues
  12. //兼容性处理,解决IE bug
  13. if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
  14. !jQuery.isXMLDoc( elem ) ) {
  15. // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
  16. destElements = getAll( clone );
  17. srcElements = getAll( elem );
  18. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  19. fixInput( srcElements[ i ], destElements[ i ] );
  20. }
  21. }
  22. // Copy the events from the original to the clone
  23. //从目标节点克隆事件,并绑定给克隆的元素
  24. if ( dataAndEvents ) {
  25. //克隆子节点的事件和数据
  26. if ( deepDataAndEvents ) {
  27. //源节点
  28. srcElements = srcElements || getAll( elem );
  29. //克隆节点
  30. destElements = destElements || getAll( clone );
  31. for ( i = 0, l = srcElements.length; i < l; i++ ) {
  32. cloneCopyEvent( srcElements[ i ], destElements[ i ] );
  33. }
  34. }
  35. //只克隆目标节点和数据
  36. else {
  37. cloneCopyEvent( elem, clone );
  38. }
  39. }
  40. //将script标签设为已运行
  41. // Preserve script evaluation history
  42. destElements = getAll( clone, "script" );
  43. if ( destElements.length > 0 ) {
  44. setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
  45. }
  46. // Return the cloned set
  47. return clone;
  48. },
  49. })

解析:
可以看到这部分源码主要分为三大块:
(1)解决 IE 的 bug,主要是在fixInput()方法上进行处理
(2)从目标节点克隆数据、添加事件给克隆的元素
(3)将克隆的元素中的script标签设为已运行

四、fixInput()
作用:
(1)解决 IE 无法保存克隆的单选、多选的状态的 bug
(2)解决 IE 无法将克隆的选项返回至默认选项状态的 bug

源码:

</>code

  1. //解决IE的bug:(1)无法保存克隆的单选、多选的状态 (2)无法将克隆的选项返回至默认选项状态
  2. // Fix IE bugs, see support tests
  3. //源码5937行
  4. function fixInput( src, dest ) {
  5. var nodeName = dest.nodeName.toLowerCase();
  6. // Fails to persist the checked state of a cloned checkbox or radio button.
  7. //IE无法保存克隆的单选框和多选框的选择状态
  8. if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
  9. dest.checked = src.checked;
  10. }
  11. //IE无法将克隆的选项返回至默认选项状态
  12. // Fails to return the selected option to the default selected state when cloning options
  13. else if ( nodeName === "input" || nodeName === "textarea" ) {
  14. dest.defaultValue = src.defaultValue;
  15. }
  16. }

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

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

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

优点是方便复制数据。

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

示意图:

源码:

</>code

  1. //src:目标元素
  2. //dest:克隆的元素
  3. //源码5902行
  4. function cloneCopyEvent( src, dest ) {
  5. var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
  6. if ( dest.nodeType !== 1 ) {
  7. return;
  8. }
  9. //拷贝jQuery内部数据:事件、处理程序等
  10. // 1. Copy private data: events, handlers, etc.
  11. if ( dataPriv.hasData( src ) ) {
  12. //private data old,即目标元素的数据
  13. //注意:jQuery是通过uuid将目标元素进行标记,
  14. //然后将与目标元素相关的数据都放到内存中
  15. //通过uuid和内存的数据建立映射
  16. //这种数据分离的做法有利于复制数据,但不能复制事件
  17. pdataOld = dataPriv.access( src );
  18. //private data current,即为克隆的元素设置数据
  19. pdataCur = dataPriv.set( dest, pdataOld );
  20. events = pdataOld.events;
  21. //如果事件存在
  22. if ( events ) {
  23. //移除克隆对的元素的处理程序和事件
  24. delete pdataCur.handle;
  25. pdataCur.events = {};
  26. //依次为克隆的元素添加事件
  27. //注意:事件是不能被复制的,所以需要重新绑定
  28. for ( type in events ) {
  29. for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  30. jQuery.event.add( dest, type, events[ type ][ i ] );
  31. }
  32. }
  33. }
  34. }
  35. // 2. Copy user data
  36. //拷贝用户数据
  37. if ( dataUser.hasData( src ) ) {
  38. udataOld = dataUser.access( src );
  39. udataCur = jQuery.extend( {}, udataOld );
  40. //为克隆的元素设置数据
  41. dataUser.set( dest, udataCur );
  42. }
  43. }

解析:
(1)拷贝 jQuery 内部数据(事件、处理程序)
拷贝赋值数据:

</>code

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

拷贝添加事件:

</>code

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

(2)拷贝用户数据

</>code

  1. dataUser.set( dest, udataCur );

六、setGlobalEval()
作用:
设置目标元素内部的

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103852.html

相关文章

  • jQuery源码解析trigger()

    摘要:一和的作用和区别触发被选元素上的指定事件以及事件的默认行为比如表单提交不会引起事件比如表单提交的默认行为触发所有匹配元素的指定事件只触发第一个匹配元素的指定事件会冒泡不会冒泡二被点击了作用看一源码触发事件,是自定义事件的额外参数源码行解析本 showImg(https://segmentfault.com/img/remote/1460000019375685); 一、$().trig...

    Youngs 评论0 收藏0
  • JS的深浅拷贝

    摘要:引用类型之所以会出现深浅拷贝的问题,实质上是由于对基本类型和引用类型的处理不同。另外方法可以视为数组对象的浅拷贝。上面描述过的复杂问题依然存在,可以说是最简陋但是日常工作够用的深拷贝方式。 一直想梳理下工作中经常会用到的深拷贝的内容,然而遍览了许多的文章,却发现对深拷贝并没有一个通用的完美实现方式。因为对深拷贝的定义不同,实现时的edge case过多,在深拷贝的时候会出现循环引用等问...

    xiaoxiaozi 评论0 收藏0
  • FE.SRC-逐行分析jQuery2.0.3源码-完整笔记

    摘要:根据项目选型决定是否开启。为了压缩,可维护为了支持从而使用代替变量存储防冲突会用到,形如版本号声明最终调用的是这个原型实际上。功能检测统一兼容性问题。 概览 (function (){ (21 , 94) 定义了一些变量和函数 jQuery=function(); (96 , 293) 给jQuery对象添加一些方法和属性; (285 , 347) ...

    Lin_R 评论0 收藏0
  • FE.SRC-逐行分析jQuery2.0.3源码-完整笔记

    摘要:根据项目选型决定是否开启。为了压缩,可维护为了支持从而使用代替变量存储防冲突会用到,形如版本号声明最终调用的是这个原型实际上。功能检测统一兼容性问题。 概览 (function (){ (21 , 94) 定义了一些变量和函数 jQuery=function(); (96 , 293) 给jQuery对象添加一些方法和属性; (285 , 347) ...

    褰辩话 评论0 收藏0

发表评论

0条评论

coolpail

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<