jQuery 源碼解析(二十二) DOM操作模塊 複製元素 詳解

来源:https://www.cnblogs.com/greatdesert/archive/2019/11/11/11814242.html
-Advertisement-
Play Games

本節說一下DOM操作模塊里的複製元素子模塊,該模塊可以複製一個DOM節點,並且可選擇的設置是否複製其數據緩存對象(包含事件信息)和是否深度複製(子孫節點等),API如下: $.clone(elem, dataAndEvents, deepDataAndEvents) ;jQuery底層方法,返回DO ...


本節說一下DOM操作模塊里的複製元素子模塊,該模塊可以複製一個DOM節點,並且可選擇的設置是否複製其數據緩存對象(包含事件信息)和是否深度複製(子孫節點等),API如下:

  • $.clone(elem, dataAndEvents, deepDataAndEvents)    ;jQuery底層方法,返回DOM引用    ;elem是要複製的DOM元素,dataAndEvents和deepDataAndEvents分別表示是否複製克隆元素的數據和事件 和 是否複製深度複製數據和事件 
  • $.fn.clone(dataAndEvents,deepDataAndEvents)        ;jQuery實例方法,返回jQuery對象    ;參數同上,如果指定了參數1,參數2為空時,則參數2等於參數1 

 writer by:大沙漠 QQ:22969969

還是先舉個慄子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
    <div style="width: 150px;height: 50px;background: #cfc;">
        <p>今天天氣很好</p>
    </div>
    <button id="b1">按鈕1</button>
    <button id="b2">按鈕2</button>
    <button id="b3">按鈕3</button>
    <button id="b4">按鈕4</button>

    <script>
        $('div').click(function(){console.log('div click');})                     //給div綁定一個click事件
        $('p').click(function(){console.log('p click');})                         //給p綁定一個click事件

        /*點擊按鈕1、按鈕2、按鈕3、按鈕4都將會複製div,並添加到body的末尾,再點擊複製出來的區塊里的p元素時輸出如下:*/
        $('#b1').click(function(){$('div').clone().appendTo('body');})            //沒有任何輸出
        $('#b2').click(function(){$('div').clone(true,false).appendTo('body');})  //輸出:clone_d1 click
        $('#b3').click(function(){$('div').clone(true,true).appendTo('body');})   //輸出:clone_p1 click、clone_d1 click
        $('#b4').click(function(){$('div').clone(true).appendTo('body');})        //輸出:clone_p1 click、clone_d1 click  ;因為參數2省略,預設等於參數1
    </script>
</body>
</html>

渲染如下:

我們在div和p上分別綁定了兩個事件,點擊p元素(今天天氣很好這個文本)控制台輸出如下:

 另外我們點擊任意一個按鈕都會克隆div元素,渲染如下:

只不過點擊克隆出來的元素的p元素,也就是箭頭點擊的文字,控制台輸出的內容不同,對於四個按鈕分別如下:

  • 按鈕1 ;無輸出                                 ;clone()未傳入參數,因此不會複製數據緩存對象
  • 按鈕2 ;輸出:一行:div click               ;clone()傳入了true和false,因此只會對div的數據緩存對象做一次拷貝,對於p就不會拷貝了
  • 按鈕3 ;輸出兩行:p click和div click  ;clone()傳入了兩個true,會進行深層次的拷貝,子孫節點的數據對象都會拷貝過來
  • 按鈕4  ;輸出兩行:p click和div click ;clone()只傳入一個true,這和按鈕3是一樣的,且看下麵代碼分析

 

源碼分析


 先介紹一下$.clone(),也就是jQuery的底層方法,如下:

jQuery.extend({
    clone: function( elem, dataAndEvents, deepDataAndEvents ) {         //複製DOM元素,並修正不相容屬性。dataAndEvents:是否複製數據和事件。deepDataAndEvents:是否複製後代元素的數據和事件。
        var srcElements,
            destElements,
            i,
            // IE<=8 does not properly clone detached, unknown element nodes
            clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?    //如果瀏覽器支持HTML5元素,或者不支持html5且原始元素不含有html5元素 
                elem.cloneNode( true ) :                                                            //調用原生方法.clone(deep)複製DOM元素 
                shimCloneNode( elem );                                                              //否則調用函數shimCloneNode()通過"安全文檔片段"複製HTML5元素

        if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&                //修正不相容性
                (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
            // IE copies events bound via attachEvent when using cloneNode.
            // Calling detachEvent on the clone will also remove the events
            // from the original. In order to get around this, we use some
            // proprietary methods to clear the events. Thanks to MooTools
            // guys for this hotness.

            cloneFixAttributes( elem, clone );

            // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
            srcElements = getAll( elem );
            destElements = getAll( clone );

            // Weird iteration because IE will replace the length property
            // with an element if you are cloning the body and one of the
            // elements on the page has a name or id of "length"
            for ( i = 0; srcElements[i]; ++i ) {
                // Ensure that the destination node is not null; Fixes #9587
                if ( destElements[i] ) {
                    cloneFixAttributes( srcElements[i], destElements[i] );
                }
            }
        }

        // Copy the events from the original to the clone
        if ( dataAndEvents ) {                      //如果複製數據和事件
            cloneCopyEvent( elem, clone );              //調用cloneCopyEvent()數據

            if ( deepDataAndEvents ) {                  //如果是深度複製
                srcElements = getAll( elem );               //獲取源DOM節點所有子節點的DOM引用
                destElements = getAll( clone );             //獲取目標DOM節點所有子節點的DOM引用

                for ( i = 0; srcElements[i]; ++i ) {        //遍歷源DOM節點的子節點
                    cloneCopyEvent( srcElements[i], destElements[i] );  //逐個複製數據緩存
                }
            }
        }

        srcElements = destElements = null;

        // Return the cloned set
        return clone;                               //最後返回clone,也就是複製出來的DOM元素
    },
})

$.clone()調用原生的cloneNode()方法拷貝了一份DOM,對於數據緩存則用cloneCopyEvent()進行拷貝,該函數實現如下:

function cloneCopyEvent( src, dest ) {      //複製數據和事件   ;$.clone()函數調用  ;src是源DOM節點,dest是目標節點

    if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {  //如果dest不是元素節點或 src不含有數據,則直接返回
        return;
    }

    var type, i, l,
        oldData = jQuery._data( src ),                      //獲取原對象內部數據
        curData = jQuery._data( dest, oldData ),            //設置目標對象的內部數據   ;這時src和dest兩個對象內的事件對象(events和handle屬性)都是指向同一個的
        events = oldData.events;                            //原對象的事件對象

    if ( events ) {                                         //如果源DOM對象有綁定事件處理函數,則刪除目標DOM對象的事件信息,再重新綁定
        delete curData.handle;                                  //刪除目標對象的監聽句柄
        curData.events = {};                                    //重置目標對象的事件列表

        for ( type in events ) {                                //遍歷源DOM對象的事件列表
            for ( i = 0, l = events[ type ].length; i < l; i++ ) {  //遍歷綁定的每個函數
                jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );   //依次在目標DOM對象上進行綁定事件操作
            }
        }
    }

    // make the cloned public data object a copy from the original
    if ( curData.data ) {                                   //如果源DOM對象含有自定義事件對象
        curData.data = jQuery.extend( {}, curData.data );       //也單獨拷貝一份,再保存到curData.data中
    }
}

在源碼里可以看到,如果有綁定了事件對象則會調用jQuery.event.add()依次進行綁定,實現就是這樣子的。

對於實例方法$.fn.clone()來說,它的實現如下:

jQuery.fn.extend({
    clone: function( dataAndEvents, deepDataAndEvents ) {           //創建匹配元素集合的深度複製副本。dataAndEvents:可選的布爾值,表示是否複製數據和事件,預設為false。deepDataAndEvents:可選的布爾值,表示是否深度複製數據和事件,預設為false。
        dataAndEvents = dataAndEvents == null ? false : dataAndEvents;                      //修正dataAndEvents參數
        deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;  //修正deepDataAndEvents參數

        return this.map( function () {                                      //調用發那個發.map()遍歷匹配元素集合,在回調函數函數中調用jQuery.clone()複製每個匹配元素。
            return jQuery.clone( this, dataAndEvents, deepDataAndEvents );      //調用底層的jQuery.clone()方法
        });
    },
})

這裡可以看到,對於$.fn.clone()來說,如果參數2沒有傳遞,則會修正未參數1,上面例子的按鈕4就是執行到這裡的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 國瑞前端: js確定取消,在html界面中,有css模擬的模態框,這樣顯示的就會更好看一些,那麼javascript有沒有自帶的彈框呢,當然是有的,接下來我就來給大家介紹一下把: js確定取消-警告框alert() 起到警告作用 js確定取消-確認框confirm() 123456789101112 ...
  • 響應式佈局 一個網站能夠相容多個終端,並且在各個終端都可以很好展示體驗。 媒體類型 在何種設備或者軟體上將頁面打開 123456789 all:所有媒體braille:盲文觸覺設備embossed:盲文印表機print:手持設備projection:印表機預覽screen:彩屏設備speech:'聽 ...
  • 小程式由來 當初結婚,為了給媳婦驚喜,藉助雲開發的推廣,自己做了一個結婚用的邀請函小程式,結完婚後,趁著空閑時間,希望把之前使用的邀請函小程式留存下來,所以做了一次整體改版。改版後的小程式我自己定義為相冊類小程式,主要放一些自己喜歡的照片。 小程式功能 首頁相冊 愛的空間相冊 陌生人的到訪 陌生人的 ...
  • 中間件是什麼呢? 中間件就是客戶端http請求發起傳送到伺服器和伺服器返迴響應之間的一些處理函數。 為什麼要使用中間件? 通過中間件,可以對數據進行操作使得我們能方便地操作請求數據編寫伺服器響應。如body-parse中間件對post請求的參數進行處理讓我們可以通過res.body快速獲取請求參數, ...
  • 一、項目簡介 uni-liveShow是一個基於vue+uni-app技術開發的集小視頻/IM聊天/直播等功能於一體的微直播項目。界面仿製抖音|火山小視頻/陌陌直播,支持編譯到多端(H5、小程式、App端) 且相容效果一致。 二、效果預覽 在H5、小程式、App端測試效果如下:(後續大圖均為APP端 ...
  • 最近在工作中遇到了一個百度地圖api中的難題,恐怕有的程式員可能也遇到過。就是實時定位並顯示軌跡,網上大部分都是通過創建polyline對象貼到地圖上。當然,百度地圖的畫線就是這樣實現的,但是好多人會發現,如果數據量超過四五千的話,瀏覽器可能就要卡了,後面可能就直接因為瀏覽器記憶體不足直接崩潰。按理講 ...
  • 文字摺疊效果 1. 效果展示 2. 實現過程 ~~~html H e l l o W o r l d ~~~ 填充內容 CSS佈局 ~~~css { margin:0px; padding:0px; } body{ background color:aquamarine; width:100%; h ...
  • 1.什麼是window? window:是一個全局對象, 代表瀏覽器中一個打開的視窗, 每個視窗都是一個window對象2.什麼是document? document是window的一個屬性, 這個屬性是一個對象 document: 代表當前視窗中的整個網頁, document對象保存了網頁上所有的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...