一览
今天是第四天啦!笔记的内容主要是跟着慕课网上的jQuery源码解析系列课程以及自己的理解+实践来写的(也比较偏向于自己的梳理,所以可能会有点乱),可能会有错误,欢迎指出。
原生的cloneNode不会复制js属性(比如:事件),但是IE会复制事件处理程序。
cloneNode(isDeep)
isDeep接受一个参数,true表示执行深拷贝,复制文本以及它的子节点树。false表示只复制节点本身。
事件处理
IE低版本会克隆原生事件,但2.1.1版本不处理兼容低级版本。
数据缓存机制:
jQuery遍历节点clone的时候,把事件和数据一并复制。
jQuery在DOM上做了一个uuid的标记,把这个dom关联的数据放在一个内存区域,通过uuid进行映射,但是事件需要重新绑定。
- elem.cloneNode(true)把元素克隆,等待加入事件和数据。
- jQuery内部数据存在data_priv中(包括事件)。data_user是提供给用户操作的。
- 把2中的两个缓存找到混入到新的节点(接口:data_prive.access和data_priv.set)
- 事件的复制通过jQuery.event.add来绑定。节点是嵌套的话需要遍历每一个元素节点进行处理。
jQuery的clone()源码:
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var i, l, srcElements, destElements,
//克隆原节点
clone = elem.cloneNode( true ),
//判断是不是文档节点
inPage = jQuery.contains( elem.ownerDocument, elem );
//浏览器单选框选中状态不能正确克隆且该elem是元素或者文档碎片,但不是XML文档的
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
!jQuery.isXMLDoc( elem ) ) {
//就进行选择状态处理(fixInput见下)
for ( i = 0, l = srcElements.length; i < l; i++ ) {
fixInput( srcElements[ i ], destElements[ i ] );
}
}
// 添加事件
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 );
}
}
// Preserve script evaluation history
destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
// Return the cloned set
return clone;
}
fixInput用来处理input元素:
function fixInput( src, dest ) {
var nodeName = dest.nodeName.toLowerCase();
//如果元素是可check的input元素
if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
//把选中的状态也复制过去
dest.checked = src.checked;
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
}
}
复制事件:
function cloneCopyEvent( src, dest ) {
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
//如果目标对象不是元素直接返回
if ( dest.nodeType !== 1 ) {
return;
}
// 1. 复制data_priv: events, handlers等
if ( data_priv.hasData( src ) ) {
//获取源元素的data_privv
pdataOld = data_priv.access( src );
//set方法返回的是cache
pdataCur = data_priv.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. 复制data_user
if ( data_user.hasData( src ) ) {
udataOld = data_user.access( src );
udataCur = jQuery.extend( {}, udataOld );
data_user.set( dest, udataCur );
}
}
更加详细的情况以后肯定会再次碰到和了解( •̀ ω •́ )今天就先在这里。