jQuery之html()的实现

2022-03-28 14:48:12 浏览数 (1)

一、有这样一段 html

代码语言:javascript复制
<div class="divOne">
  <p>嘿嘿嘿</p>
</div>
<div class="divOne">
  <p>哈哈哈</p>
</div>

二、jQuery 的 html() 方法 (1)当直接调用 $().html()时,.html()的作用是只读取第一个目标元素的innerHTML

简单实现:

代码语言:javascript复制
  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

简单实现:

代码语言:javascript复制
  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)源码实现 源码:

代码语言:javascript复制
  // 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部分源码:

代码语言:javascript复制
  //$().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()的情况调用这部分源码:

代码语言:javascript复制
      if ( value === undefined && elem.nodeType === 1 ) {
        return elem.innerHTML;
      }

.html("字符串")/.html("<p>这也是字符串</p>")的情况调用这部分源码:

代码语言:javascript复制
        // 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(这里面是标签)的情况调用这部分源码: 标签:

代码语言:javascript复制
  let p=document.createElement('p')
  p.innerText='哈哈哈'
  $(".divOne").html(p)

源码:

代码语言:javascript复制
      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(标签)

源码:

代码语言:javascript复制
<!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>

0 人点赞