2

一览

今天是第四天啦!笔记的内容主要是跟着慕课网上的jQuery源码解析系列课程以及自己的理解+实践来写的(也比较偏向于自己的梳理,所以可能会有点乱),可能会有错误,欢迎指出。

原生的cloneNode不会复制js属性(比如:事件),但是IE会复制事件处理程序。

cloneNode(isDeep)

isDeep接受一个参数,true表示执行深拷贝,复制文本以及它的子节点树。false表示只复制节点本身。

事件处理

IE低版本会克隆原生事件,但2.1.1版本不处理兼容低级版本。

数据缓存机制
jQuery遍历节点clone的时候,把事件和数据一并复制。
jQuery在DOM上做了一个uuid的标记,把这个dom关联的数据放在一个内存区域,通过uuid进行映射,但是事件需要重新绑定。

  1. elem.cloneNode(true)把元素克隆,等待加入事件和数据。
  2. jQuery内部数据存在data_priv中(包括事件)。data_user是提供给用户操作的。
  3. 把2中的两个缓存找到混入到新的节点(接口:data_prive.access和data_priv.set)
  4. 事件的复制通过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 );
    }
}

更加详细的情况以后肯定会再次碰到和了解( •̀ ω •́ )今天就先在这里。


MOCHIKO
318 声望29 粉丝

引用和评论

0 条评论