jQuery之html()的實現

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

jQuery之html()的實現

一、有這樣一段 html

<div class="divOne">
  <p>嘿嘿嘿</p>
</div>
<div class="divOne">
  <p>哈哈哈</p>
</div>
複製程式碼

二、jQuery 的 html() 方法

(1)當直接呼叫 $().html()時,.html()的作用是隻讀取第一個目標元素的innerHTML

簡單實現:

  function customHtml(value) {
    //預設是選取第一個目標元素
    let elem = this[0] || {},
      i = 0,
      l = this.length;
    //如果是html(),即使讀取目標元素的innerHTML的話
    if (value === undefined && elem.nodeType === 1) {
      return elem.innerHTML;
    }
    //xxx
    //xxx
  }
複製程式碼

(2)當呼叫$().html(value)時,.html()的作用是為每一個符合條件的目標元素的innerHTML設定為 value

簡單實現:

  function customHtml(value) {
    //預設是選取第一個目標元素
    let elem = this[0] || {},
      i = 0,
      l = this.length;
    //如果是html(),即使讀取目標元素的innerHTML的話
    if (value === undefined && elem.nodeType === 1) {
      return elem.innerHTML;
    }
    //根據目標元素的個數,依次對符合條件的目標元素賦值
    for (; i < l; i++) {
      elem = this[i] || {};
      if (elem.nodeType === 1) {
        elem.innerHTML = value;
      }
    }
  }
複製程式碼

(3)原始碼實現

原始碼:

  // html()方法設定或返回被選元素的內容(innerHTML)
  // 當該方法用於返回內容時,則返回第一個匹配元素的內容
  // 當該方法用於設定內容時,則重寫所有匹配元素的內容
  // http://www.runoob.com/jquery/html-html.html
  // 原始碼6203行左右
  function html( value ) {
    //呼叫$().html()方法,即呼叫access()方法
    //關於access()方法的講解,請看:https://www.cnblogs.com/gongshunkai/p/5905917.html
    //access(this,function(),null,value,arguments.length)
    return jQuery.access( this, function( value ) {
      //讀的話(.html())只讀第一個匹配的目標元素的內容所以是this[0]
      //寫的話(.html(xxx))會迴圈每個匹配的目標並將其innerHTML置為value
      var elem = this[ 0 ] || {},
        i = 0,
        l = this.length;
      //當直接呼叫html(),並且目標元素是元素節點時,$().html()的本質是 selector.innerHTML
      if ( value === undefined && elem.nodeType === 1 ) {
        return elem.innerHTML;
      }

      // See if we can take a shortcut and just use innerHTML
      //如果能直接使用innerHTML來解析的話
      //注意:IE的innerHTML會忽略開頭的無作用域元素
      if ( typeof value === "string" &&
        !rnoInnerhtml.test( value ) &&
        !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
        //Hello <b>world</b>!
        value = jQuery.htmlPrefilter( value );
        console.log(value,'value6235')
        try {
          for ( ; i < l; i++ ) {
            elem = this[ i ] || {};

            // Remove element nodes and prevent memory leaks

            if ( elem.nodeType === 1 ) {
              console.log(3333,'node6261')
              // getAll( elem, false ):獲取原本selector內部的內容(標籤)
              //先移除元素節點和註冊的事件以防止記憶體洩漏
              jQuery.cleanData( getAll( elem, false ) );

              elem.innerHTML = value;
            }
          }
          //將elem置為0,是防止執行下面的if(elem)...
          elem = 0;

          // If using innerHTML throws an exception, use the fallback method
        } catch ( e ) {}
      }

      if ( elem ) {
        this.empty().append( value )
      }
    }, null, value, arguments.length )
  }
複製程式碼

原始碼解析:

① 呼叫html(),實際上是呼叫access()

access部分原始碼:

  //$().html():access(this,function(),null,value,arguments.length)
  //原始碼4051行
  //關於access()方法的講解,請看:https://www.cnblogs.com/gongshunkai/p/5905917.html
  var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
    var i = 0,
      //1
      len = elems.length,
      //true
      bulk = key == null;

    // Sets many values
    if ( toType( key ) === "object" ) {
        //xxx
    } else if ( value !== undefined ) {
      console.log('access->value!==undefined','value4053')
      chainable = true;
      //xxx
      if ( bulk ) {
        // Bulk operations run against the entire set
        //走這邊
        if ( raw ) {
          // 將elems/selector,value傳入function並執行
          // call(this,param)
          fn.call( elems, value );
          //這裡將 function 置為空值後,就不會執行 if(fn)...了
          fn = null;
          // ...except when executing function values
        }
        //不走這邊
        else {
          bulk = fn;
          fn = function( elem, key, value ) {
            return bulk.call( jQuery( elem ), value );
          };
        }
      }
    //xxx
    //xxx
    //xxx
  };
複製程式碼

也就是說:呼叫jQuery.access()相當於呼叫了fn.call( elems, value ),即自定義的方法jQuery.access(this, function(value) {xxx})

.html()的情況呼叫這部分原始碼:

      if ( value === undefined && elem.nodeType === 1 ) {
        return elem.innerHTML;
      }
複製程式碼

.html("字串")/.html("<p>這也是字串</p>")的情況呼叫這部分原始碼:

        // See if we can take a shortcut and just use innerHTML
        //如果能直接使用innerHTML來解析的話
        //注意:IE的innerHTML會忽略開頭的無作用域元素
        if ( typeof value === "string" && 
          !rnoInnerhtml.test( value ) &&
          !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
          //Hello <b>world</b>!
          value = jQuery.htmlPrefilter( value );
          console.log(value,'value6235')
          try {
            for ( ; i < l; i++ ) {
              elem = this[ i ] || {};
              // Remove element nodes and prevent memory leaks
              if ( elem.nodeType === 1 ) {
                console.log(3333,'node6261')
                // getAll( elem, false ):獲取原本selector內部的內容(標籤)
                //先移除元素節點和註冊的事件以防止記憶體洩漏
                jQuery.cleanData( getAll( elem, false ) );
                elem.innerHTML = value;
              }
            }
            //將elem置為0,是防止執行下面的if(elem)...
            elem = 0;
            // If using innerHTML throws an exception, use the fallback method
          } catch ( e ) {}
        }
複製程式碼

.html(這裡面是標籤)的情況呼叫這部分原始碼:

標籤:

  let p=document.createElement('p')
  p.innerText='哈哈哈'
  $(".divOne").html(p)
複製程式碼

原始碼:

      if ( elem ) {
        this.empty().append( value );
      }
複製程式碼

⑤ 總結 $(".divOne").html()本質$(".divOne")[0].innerHTML

$(".divOne").html("Hello <b>world</b>!")本質$(".divOne")[i].innerHTML="Hello <b>world</b>!"

$(".divOne").html(標籤)本質$(".divOne").empty().append(標籤)

原始碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>jQuery之html()</title>
</head>
<body>
<script src="jQuery.js"></script>
<div class="divOne">
  <p>嘿嘿嘿</p>
</div>
<div class="divOne">
  <p>嘿嘿嘿</p>
</div>
<input type="text" id="inputOne">
<script>
  function customHtml(value) {
    //預設是選取第一個目標元素
    let elem = this[0] || {},
      i = 0,
      l = this.length;
    //如果是html(),即使讀取目標元素的innerHTML的話
    if (value === undefined && elem.nodeType === 1) {
      return elem.innerHTML;
    }
    //根據目標元素的個數,依次對符合條件的目標元素賦值
    for (; i < l; i++) {
      elem = this[i] || {};
      if (elem.nodeType === 1) {
        elem.innerHTML = value;
      }
    }
  }
  // html()方法設定或返回被選元素的內容(innerHTML)
  // 當該方法用於返回內容時,則返回第一個匹配元素的內容
  // 當該方法用於設定內容時,則重寫所有匹配元素的內容
  // http://www.runoob.com/jquery/html-html.html
  // 原始碼6203行左右
  function html( value ) {
    //呼叫$().html()方法,即呼叫access()方法
    //關於access()方法的講解,請看:https://www.cnblogs.com/gongshunkai/p/5905917.html
    //access(this,function(),null,value,arguments.length)
    return jQuery.access( this, function( value ) {
      //讀的話(.html())只讀第一個匹配的目標元素的內容所以是this[0]
      //寫的話(.html(xxx))會迴圈每個匹配的目標並將其innerHTML置為value
      var elem = this[ 0 ] || {},
        i = 0,
        l = this.length;
      //當直接呼叫html(),並且目標元素是元素節點時,$().html()的本質是 selector.innerHTML
      if ( value === undefined && elem.nodeType === 1 ) {
        return elem.innerHTML;
      }

      // See if we can take a shortcut and just use innerHTML
      //如果能直接使用innerHTML來解析的話
      //注意:IE的innerHTML會忽略開頭的無作用域元素
      if ( typeof value === "string" &&
        !rnoInnerhtml.test( value ) &&
        !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
        //Hello <b>world</b>!
        value = jQuery.htmlPrefilter( value );
        console.log(value,'value6235')
        try {
          for ( ; i < l; i++ ) {
            elem = this[ i ] || {};

            // Remove element nodes and prevent memory leaks

            if ( elem.nodeType === 1 ) {
              console.log(3333,'node6261')
              // getAll( elem, false ):獲取原本selector內部的內容(標籤)
              //先移除元素節點和註冊的事件以防止記憶體洩漏
              jQuery.cleanData( getAll( elem, false ) );

              elem.innerHTML = value;
            }
          }
          //將elem置為0,是防止執行下面的if(elem)...
          elem = 0;

          // If using innerHTML throws an exception, use the fallback method
        } catch ( e ) {}
      }

      if ( elem ) {
        this.empty().append( value );
      }
    }, null, value, arguments.length );
  }


  customHtml.call(document.querySelectorAll(".divOne"))
  customHtml.call(document.querySelectorAll(".divOne"),"Hello <b>world</b>!")
  // console.log($(".divOne").html())
  // $(".divOne").html("Hello <b>world</b>!")
  // let p=document.createElement('p')
  // p.innerText='哈哈哈gggg'
  // $(".divOne").html(p)
  // console.log(p,'p19')
  // $("#divOne").text('<p>aaaa</p>')
  // $("#divOne").text(p)

</script>
</body>
</html>
複製程式碼

jQuery之html()的實現

(完)

相關文章