jQueryソース分析のwrap,wrapInner,wrapAll,unwrap方法

8272 ワード

まずeachインスタンスメソッドの使い方を思い出します.
<html>
<head>
<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
  $("button").click(function(){
    $("li").each(function(i,elem){
     //    each     ,            ,          DOM  
     //this        DOM  !
    });
  });
});
</script>
</head>
<body>
<button>         </button>
<ul>
<li>Coffee</li>
<li>Milk</li>
<li>Soda</li>
</ul>
</body>
</html>
contentsメソッドの使い方をもう一度思い出します:クリックしてリンクを開きます
contents: function( elem ) {  
//           DOM  ,   iframe    contentDocument          childNodes   NodeList
        return jQuery.nodeName( elem, "iframe" ) ?  
            elem.contentDocument || elem.contentWindow.document :  
            jQuery.merge( [], elem.childNodes );  
    }  

html要素を参照:
<div class="parent">
	<div class="test">
		111111
	</div>
	<div class="test">
		22222222
	</div>
</div>
<span class="test"></span>
 
 

wrapAll源码分析:

结论:(如果调用对象所有DOM元素位置不相邻,那么会把他们移动到第一个匹配元素的位置,然后包裹起来)

我们测试代码如下:

$(document).ready(function()
{
  $('.test').wrapAll("<em style='color:red'><span>Hello you</span></em>");
});
この場合、修正されたhtml構造は以下のようになります.
<div class="parent">
	<em style="color:red">
             <span>Hello you
              <div class="test">
		111111
	        </div>
               <div class="test">
		22222222
	     </div>
      <span class="test"></span>
    </span>
    </em>
</div>
この例では、次の点に注意します.
(1)我々の呼び出しオブジェクトはすべて新しく作成されたオブジェクトのサブ要素として現れる.ソースコードに基づいて、最初のステップは私たちが新しく作成したオブジェクトを最初の呼び出しオブジェクトの一番前に置いて、2番目のステップはすべての呼び出しオブジェクトをappendを通じて私たちが新しく作成したオブジェクトの下に入れます!(2)呼び出しオブジェクトのDOM要素はwrapAllを呼び出す前にspan要素はparentの兄弟ノードだったが,呼び出し後はサブノードになったように位置移動する可能性がある.これは,既に存在するノードがDOMの他の位置に挿入されると,そのDOMが元の位置から消えるためである.
jQuery.fn.extend({	
	wrapAll1: function( html ) {
		//     ,               ,             DOM
		//           DOM  ,              wrapAll  
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				jQuery(this).wrapAll( html.call(this, i) );
			});
		}
       //       DOM    
		if ( this[0] ) {
			// The elements to wrap the target around
			// html     ,           jQuery      
			//       ,          DOM  ,             ! ownerDocument       !
			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
			//alert(wrap.attr("style"));
           //         DOM    , id="parent"  
		   //insertBefore      ,              
			//alert(this[0].parentNode.className);
			if ( this[0].parentNode ) {
				//wrap jQuery  ,  insertBefore  ,      wrap    wrapAll         !
				wrap.insertBefore( this[0] );
			}		
			//alert(this[0].parentNode.innerHTML);       .test      !
             //        DOM  ,        ,          DOM  
			//alert(wrap.attr("style"));
			//alert(wrap.html());
			//alert(wrap[0].outerHTML);
			//alert(wrap[0].parentNode.outerHTML);
			$("#result1").html(wrap[0].parentNode.outerHTML);
			var result=wrap.map(function() {	
				var elem = this;
                 // alert( elem.firstChild);
                //       wrap DOM             
				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
					elem = elem.firstChild;
				}
               //            wrapAll        !
				return elem;
			});
			//alert(result.attr("style"));
	// result        wrapAll      !    wrapAll          result       !
			//alert(result[0].outerHTML);
			result.append(this);
		}
		return this;
	}
})
//$(".test").wrapAll1("<em style='color:red'></em>");
$(".test").wrapAll1("<em style='color:red'><span>Hello you</span></em>");
 
 

wrapInner源码分析:

wrapInner: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function(i) {
				//        ,           DOM        
				//            DOM  ,      DOM    
				//                     wrapInner  !
				jQuery(this).wrapInner( html.call(this, i) );
			});
		}
		return this.each(function() {
			// DOM     jQuery  
			var self = jQuery( this ),
			//  jQuery     ,   iframe  contentDocument    childNodes
				contents = self.contents();
               //             wrapAll  ,        html       wrapInner
		//    。  wrapAll             ,wrapInner                  !       
		 //            !
			if ( contents.length ) {
				contents.wrapAll( html );
			} else {
				//         append    ,          !
				self.append( html );
			}
		});
	}

それとも上のHTMLコードなのか、wrapInnerメソッドを呼び出します.
$(document).ready(function()
{
  $('.test').wrapInner("<em style='color:red'><span>Hello you</span></em>");
});
この方法を呼び出すとDOM構造は次のようになることが分かった.
<div class="parent">
	<div class="test">
            <em style="color:red">
                 <span>Hello you
		111111
	        </span>
           </em>
        </div>
	<div class="test">
          <em style="color:red">
              <span>Hello you
		22222222
	       </span>
         </em>
      </div>
</div>
実際の結果もよく理解されています.wrapInnerでは、最初のステップは呼び出しオブジェクトごとのcontentsを取得し、2番目のステップはwrapAllメソッドを呼び出して、私たちが入力したパラメータでcontentsをすべて包みます.結果は簡単です
つまり、各呼び出しオブジェクトのcontentsはすべて私たちのパラメータオブジェクトに包まれています!
wrapメソッドソース分析:
	wrap: function( html ) {
		var isFunction = jQuery.isFunction( html );
		return this.each(function(i) {
			//     ,             wrapAll  ,         
			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
		});
	}

ソースコード解析により,wrapメソッドもwrapAllメソッドを呼び出し,その結果,パラメータは呼び出しオブジェクトの内容ではなく呼び出しオブジェクトごとに包まれることも分かった.また、wrapメソッドを手動で呼び出して、結果を見てみましょう.
$(document).ready(function()
{
  $('.test').wrap("<em style='color:red'><span>Hello you</span></em>");
});
修正後のhtmlは以下の通りです.
<div class="parent">
	<em style="color:red">
             <span>Hello you
                 <div class="test">
		111111
	        </div>
             </span>
         </em>
	<em style="color:red">
             <span>Hello you
                  <div class="test">
		22222222
	           </div>
             </span>
        </em>
</div>
明らかに、wrapメソッドとwrapInnerメソッドの違いは、次のとおりです.
wrapInnerメソッドは各呼び出しオブジェクトの内容をパラメータで包み、wrapメソッドはパラメータで各呼び出しオブジェクトを含む!
unwrapメソッドソース分析:(このメソッドは現在の一致する要素の親要素を除去しますが、内部のサブ要素はすべて保持されますが、body要素は除去されません!)
unwrap: function() {
		//   body   parents      
		return this.parent().each(function() {
			if ( !jQuery.nodeName( this, "body" ) ) {
				//  parents    DOM     jQuery  ,  replaceWith  
				//        !,    end  
				jQuery( this ).replaceWith( this.childNodes );
			}
		}).end();//     end       parent       ,    end     this,       ,        
                       //    end               , end           

まとめ:
(1)wrapAllはすべての呼び出しオブジェクトをパラメータで包み、最後にすべての呼び出しオブジェクトがパラメータとなる最後のサブ要素に達し、呼び出しオブジェクトが隣接していないと移動します!
(2)wrapInnerはパラメータで各呼び出しオブジェクトのサブ要素(呼び出しオブジェクトはこのパラメータオブジェクトの外層の1層に包まれている)を含み、呼び出しオブジェクトが隣接していなければ移動しない!
(3)wrapは呼び出しパラメータを使用して各呼び出しオブジェクト(サブ要素ではない)を包み、オブジェクトが隣接していなければ移動しない.eachによって1つずつ包まれているからだ.
wrapAll vs wrap:
同じ点:すべて外層で包まれています(wrapは内部でwrapAllを呼び出します)
異なる点:wrapは1つの小包で、wrapAllは一緒に小包です!
注意:wrapInnerだけが小包サブエレメントです!