【筆記】jQuery源碼(文檔處理4)

一覽

今天是第四天啦!筆記的內容主要是跟着慕課網上的jQuery源碼解析系列課程以及本身的理解+實踐來寫的(也比較偏向於本身的梳理,因此可能會有點亂),可能會有錯誤,歡迎指出。node

原生的cloneNode不會複製js屬性(好比:事件),可是IE會複製事件處理程序。瀏覽器

cloneNode(isDeep)

isDeep接受一個參數,true表示執行深拷貝,複製文本以及它的子節點樹。false表示只複製節點自己。緩存

事件處理

IE低版本會克隆原生事件,但2.1.1版本不處理兼容低級版本。dom

數據緩存機制
jQuery遍歷節點clone的時候,把事件和數據一併複製。
jQuery在DOM上作了一個uuid的標記,把這個dom關聯的數據放在一個內存區域,經過uuid進行映射,可是事件須要從新綁定。ui

  1. elem.cloneNode(true)把元素克隆,等待加入事件和數據。
  2. jQuery內部數據存在data_priv中(包括事件)。data_user是提供給用戶操做的。
  3. 把2中的兩個緩存找到混入到新的節點(接口:data_prive.access和data_priv.set)
  4. 事件的複製經過jQuery.event.add來綁定。節點是嵌套的話須要遍歷每個元素節點進行處理。

jQuery的clone()源碼:lua

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元素:code

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 );
    }
}

更加詳細的狀況之後確定會再次碰到和了解( •̀ ω •́ )今天就先在這裏。接口

相關文章
相關標籤/搜索