jQuery 源碼解析(二十四) DOM操做模塊 包裹元素 詳解

本節說一下DOM操做模塊裏的包裹元素子模塊,該模塊可將當前匹配的元素替換指定的DOM元素,有以下方法:html

  • wrap(html)               ;在每一個匹配元素的外層添加一層DOM元素                                ;該方法會遍歷匹配元素集合,在每一個元素上調用.wrapAll()方法        ;不一樣於wrapAll()的是該方法會在每一個匹配元素外面都套一層html元素。
  • wrapAll(html)            ;會將html轉化爲一個DOM節點並放在第一個匹配元素的前面,再把其餘匹配元素也依次放進去    ;html能夠是html片斷、選擇器表達式、jQuery對象、DOM元素或函數,下同。
  • wrapInner(html)        ;在每一個匹配元素的內容先後包裹HTML元素    ;該方法會遍歷匹配元素集合,並經過調用方法.wrapAll()爲每一個匹配元素的全部內容包裹一段HTML結構。
  • unwrap()                  ;移除匹配元素集合中每一個元素的父標籤,並把匹配元素留在父元素的位置上

舉個栗子:node

 writer by:大沙漠 QQ:22969969jquery

<!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>
    <p>你好</p>
    <p>Hello World</p>
    <div>
        <i>
            <span>測試文本</span>
        </i>
    </div>

    <button id="b1">按鈕1</button> <br/>
    <button id="b2">按鈕2</button><button id="b3">按鈕3</button> <br/>
    <button id="b4">按鈕4</button><br/><button id="b5">按鈕5</button>
    <script>
        b1.onclick=function(){$('p').wrap('<div></div>')}              //內部將<div></div>轉化爲jQuery對象放到第一個匹配元素<p>你好</p>以前,再將匹配元素移動到該DOM節點內部

        b2.onclick=function(){$('p').wrapAll('<div></div>')}           //內部將<div></div>轉化爲jQuery對象放到第一個匹配元素<p>你好</p>以前,再將匹配元素移動到該DOM節點內部
        b3.onclick=function(){$('p').wrapAll('<div><p></p></div>')}    //若是含有子節點,則會將匹配元素移動到子節點裏面

        b4.onclick=function(){$('p').wrapInner('<div></div>')}         //在每一個匹配元素的內容先後添加一層DOM節點(包裹層)

        b5.onclick=function(){$('span').unwrap() }                     //移除每一個匹配元素的父元素,並讓匹配元素佔有該節點位置
    </script>
</body>
</html>

渲染以下:app

 對應的DOM樹以下:函數

 點擊按鈕1會在全部的P標籤上加一個div父節點,以下:源碼分析

 點擊按鈕2將在第一個p標籤前添加一個div,而後把全部p標籤放到div之下,以下:測試

 點擊按鈕3將在第一個p標籤前添加一個div>p雙層DOM,而後把全部p標籤放到div之下,以下:this

 點擊按鈕4將在p標籤內最外層嵌套一層div標籤,以下:spa

 點擊按鈕5將會去除 span的上一層DOM節點,以下:code

 若是再次點擊,會將span的上一層DOM繼續移除,直到遇到body節點爲止

 

源碼分析


wrapInner和wrap都是基於wrapAll實現的,wrapAll實現以下:

jQuery.fn.extend({
    wrapAll: function( html ) {                //在匹配的元素外面放置html元素。html參數能夠是html片斷、選擇器表達式、jQuery對象、DOM元素或函數。
        if ( jQuery.isFunction( html ) ) {        //若是html是函數
            return this.each(function(i) {
                jQuery(this).wrapAll( html.call(this, i) );    //遍歷匹配元素,在每一個匹配元素上執行html函數,並用該函數的返回值做爲參數迭代調用.wrapAll()函數。
            });
        }

        if ( this[0] ) {                        //若是當前有匹配元素
            // The elements to wrap the target around
            var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);        //將html轉化爲一個jQuery對象

            if ( this[0].parentNode ) {                                                //若是當前第一個匹配元素有父元素,
                wrap.insertBefore( this[0] );                                            //則把建立的包裹元素插入第一個匹配元素以前。
            }

            wrap.map(function() {                            //遍歷wrap元素
                var elem = this;                                //elem是建立的包裹元素的引用

                while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {    //若是html裏含有一個子節點
                    elem = elem.firstChild;                                            //則重置elem爲html的子節點,上面的按鈕3會執行到這裏
                }

                return elem;
            }).append( this );                                    //這一行的this是當前匹配的jQuery對象,把每一個匹配元素移動到插入的元素以後
        }

        return this;
    },
})

wrapAll首先會把參數轉化爲一個jQuery對象,而後插入到當前第一個匹配元素的前面,最後以生成的jQuery對象爲主句,調用append()將當前匹配匹配的全部元素添加到新生成的jQuery對象對應的DOM節點內部。對應上面的按鈕2

wrap()實現以下:

jQuery.fn.extend({
    wrap: function( html ) {                //在每一個匹配元素的外層添加一層DOM元素
        var isFunction = jQuery.isFunction( html );        //在每一個匹配元素先後包裹一段HTML結構,該方法會遍歷匹配元素集合,在每一個元素上調用.wrapAll()方法。
        return this.each(function(i) {
            jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );    //依次調用wrapALl()函數
        });
    },
})

wrapInner的實現以下:

jQuery.fn.extend({
    wrapInner: function( html ) {            //用於在匹配元素集合中每一個元素的內容先後包裹一段HTML結構,該方法會遍歷匹配元素集合
        if ( jQuery.isFunction( html ) ) {                //若是html是函數
            return this.each(function(i) {
                jQuery(this).wrapInner( html.call(this, i) );    //遍歷匹配元素,在每一個匹配元素上執行html函數,並用該函數的返回值做爲參數迭代調用.wrapInner()函數。
            });
        }

        return this.each(function() {                    //遍歷匹配元素集合
            var self = jQuery( this ),
                contents = self.contents();                    //先獲取全部子節點

            if ( contents.length ) {                        //若是有子節點
                contents.wrapAll( html );                        //調用wrapAll(html)爲當前元素的全部內容包裹一段HTML代碼。
            } else {
                self.append( html );                        //若是當前元素沒有內容,則直接將參數html插入當前內容。
            }
        });
    },
})

unwrap的實現以下:

Query.fn.extend({
    unwrap: function() {                        //移除匹配元素集合中每一個元素的父標籤,並把匹配元素留在父元素的位置上
        return this.parent().each(function() {            //先遍歷父節點
            if ( !jQuery.nodeName( this, "body" ) ) {        //若是不是body元素
                jQuery( this ).replaceWith( this.childNodes );    //則調用replaceWith將this.childNodes替換爲this,注意,這裏的this上下文是父節點
            }
        }).end();
    }
})
相關文章
相關標籤/搜索