jQuery原始碼解析之replaceWith()/unwrap()

進擊的小進進發表於2019-04-09

jQuery原始碼解析之replaceWith()/unwrap()

前言:當我呼叫了$().append()後,jQuery內部發生了什麼? 一樣,replaceWith() 會經過 domManip()buildFragment() 的洗禮,最後呼叫原生JS的方法來實現。

所以,本文只講述 jQuery 中最後對 replaceWith() 處理的相關程式碼。

想了解domManip()buildFragment()的,請看 當我呼叫了$().append()後,jQuery內部發生了什麼?

一、示例程式碼

<body>
<script src="jQuery.js"></script>
<div id="divTwo">
  <p id="pTwo">這是divTwo</p>
</div>
<div id="divOne">
  <p>這是divOne</p>
</div>

<script>
  let divOne = document.querySelector("#divOne")
  let divTwo = document.querySelector("#divTwo")
  let pTwo = document.querySelector("#pTwo")
  
  // ===========replaceWith==============
  //注意:removedNode指向已經被移除的divTwo
  let removedNode=$("#divTwo").replaceWith("<span>永遠</span>")
  console.log(removedNode,'removedNode21')
  //======相當於=====
  let spanA=document.createElement("span")
  spanA.innerText="永遠"
  divTwo.parentNode.replaceChild(spanA,divTwo)
  
  // ==============unwrap================
  $("#pTwo").unwrap()
  //======相當於=====
  let pTwoFather=pTwo.parentNode
  if(pTwoFather.nodeName.toLowerCase()!=='body'){
    pTwoFather.parentNode.replaceChild(pTwo,pTwoFather)
  }
  
</script>
</body>
複製程式碼

二、$().replaceWith()

作用:

把被選元素替換為新的內容

注意:$().replaceWith() 指向已經被移除的元素。

原始碼:

    // 原始碼6324行
    // 把被選元素替換為新的內容
    replaceWith: function() {
      var ignored = [];
      // Make the changes, replacing each non-ignored context element with the new content
      return domManip( this, arguments, function( elem ) {
        //獲取選擇器的父節點
        var parent = this.parentNode;
        //$.inArray() 函式用於在陣列中查詢指定值,並返回它的索引值(如果沒有找到,則返回-1)
        //inArray() 可以看成是indexOf()
        //如果ignored陣列中沒有目標元素的話
        if ( jQuery.inArray( this, ignored ) < 0 ) {
          //清除目標元素的事件
          jQuery.cleanData( getAll( this ) );
          if ( parent ) {
            //原生JS方法replaceChild(newnode,oldnode) 將某子節點替換成另一個
            parent.replaceChild( elem, this );
          }
        }
        // Force callback invocation
      }, ignored );
    }
複製程式碼

解析:

① 先找到目標元素的父節點 this.parentNode

② 使用 $.cleanData() 清除目標元素上的 事件和快取jQuery.cleanData( getAll( this ) )

③ 當父節點存在時,父節點調動replaceChild(),將待替換的元素 替換到 目標元素上

簡單實現:

  //注意:removedNode指向已經被移除的divTwo
  let removedNode=$("#divTwo").replaceWith("<span>永遠</span>")
  console.log(removedNode,'removedNode21')
  //======相當於=====
  let spanA=document.createElement("span")
  spanA.innerText="永遠"
  divTwo.parentNode.replaceChild(spanA,divTwo)
複製程式碼

三、$().inArray()

作用:

檢視元素在陣列中的位置

原始碼:

    //原始碼453行,檢視元素在陣列中的位置
    inArray: function( elem, arr, i ) {
      //indexOf:array.indexOf
      return arr == null ? -1 : indexOf.call( arr, elem, i );
    },
複製程式碼

四:$().unwrap()

作用:

移除被選元素的父元素(父節點是body則無效

原始碼:

    //原始碼9798行
    //移除被選元素的父元素(父節點是body則無效)
    unwrap: function( selector ) {
      //選中目標元素的父節點(除了body)
      this.parent( selector ).not( "body" ).each( function() {
        //this表示父節點
        //即父節點被它的子節點替換
        jQuery( this ).replaceWith( this.childNodes );
      } );
      return this;
    }
複製程式碼

解析:

是在目標元素的爺爺節點上呼叫 replaceWith() 方法,將父節點替換成目標節點。

注意:目標元素的父節點是body的話,$().unwrap()方法無效。

簡單實現:

  $("#pTwo").unwrap()
  //======相當於=====
  let pTwoFather=pTwo.parentNode
  if(pTwoFather.nodeName.toLowerCase()!=='body'){
    pTwoFather.parentNode.replaceChild(pTwo,pTwoFather)
  }
複製程式碼

五、$().parent()

作用:

返回被選元素的直接父元素

原始碼:

    //原始碼3245行
    //11表示文件碎片
    //返回被選元素的直接父元素
    parent: function( elem ) {
      var parent = elem.parentNode;
      return parent && parent.nodeType !== 11 ? parent : null;
    },
複製程式碼

這個一看就懂,就不解釋了


jQuery原始碼解析之replaceWith()/unwrap()

(完)

相關文章