jQuery中的DOM操作通过jQuery源代码分析(1.11.3)(不建议新手看)

jQuery中的DOM操作通过jQuery源代码分析

1.版本问题

jQuery有三个大版本

  • 1.x.x(兼容ie678),现在不提供更新
  • 2.x.x(不兼容IE678),现在也不提供更新了
  • 3.x.x (不兼容IE678),现在有更新
  • 国内基本都使用1.x.x版本,原因就是兼容性的问题。 我下载的是1.x.x的最后一版(1.11.3)

其他还有一些介绍在我的另一篇博客中有介绍,这里就不赘述了。
jQuery介绍及各版本介绍(适合新手查看)

2.阅读源码

从这周二开始读jQuery,虽然才读了两千多行(一共10382行),但是已经有了很大的收获。其明晰的结构,高内聚、低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷、渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。另外,阅读源码让我接触到了大量底层的知识。

1. 首先我们看看DOM操作有哪些

- 创建元素
- 插入元素
- 复制元素
- 替换元素
- 包裹元素
- 删除元素

2. 我们再来看看分别对应的方法是什么

创建元素
// $(htmlStr)
// htmlStr:html格式的字符串
$('<span-这是一个span元素</span-');
添加元素
append  appendTo	在被选元素的结尾插入内容
prepend prependTo	在被选元素的开头插入内容
before				在被选元素之后插入内容
after				在被选元素之前插入内容

清空节点与删除节点

  • empty:清空指定节点的所有元素,自身保留(清理门户)
$('div').empty(); // 清空div的所有内容(推荐使用,会清除子元素上绑定的内容,源码)
$('div').html('');// 使用html方法来清空元素,不推荐使用,会造成内存泄漏,绑定的事件不会被清除。
  • remove:相比于empty,自身也删除(自杀)
$('div').remove();

复制元素

  • 作用:复制匹配的元素
// 复制$(selector)所匹配到的元素(深度复制)
// cloneNode(true)
// 返回值为复制的新元素,和原来的元素没有任何关系了。即修改新元素,不会影响到原来的元素。
$(selector).clone();

替换元素

  • 作用:替换页面中的元素
// 替换一共有两种方法
$(selector).replaceWith(content);//selector必选,表示要替换的元素,content必选,表示要替换的内容
$(selector).replaceAll(content);//用法于上面一样

包裹元素

  • 作用:将页面中某个元素或者节点用其他元素包裹起来
$(selector).wrap(wrapper);//selector必选,表示要被包裹的元素或者节点,wrapper必选,可能的值有HTML代码,已有的元素,新元素;

再来看看jQuery中这些内容的源码

jQuery.fn.extend({//这里这么写的目的是直接通过jQuery($也可以调用)
    text: function (value) {//设置内容
      return access(this, function (value) {//下面是  条件?选择1:选择2的结构
        return value === undefined ?
          jQuery.text(this) :
          this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value));
      }, null, value, arguments.length);
    },
	//这里是插入
    append: function () {
      return this.domManip(arguments, function (elem) {
        if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
          var target = manipulationTarget(this, elem);
          target.appendChild(elem);
        }
      });
    },
	//插入到开头
    prepend: function () {
      return this.domManip(arguments, function (elem) {
        if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
          var target = manipulationTarget(this, elem);
          target.insertBefore(elem, target.firstChild);
        }
      });
    },
	//插入到选中元素之前
    before: function () {
      return this.domManip(arguments, function (elem) {
        if (this.parentNode) {
          this.parentNode.insertBefore(elem, this);
        }
      });
    },
	//插入到选中元素之后
    after: function () {
      return this.domManip(arguments, function (elem) {
        if (this.parentNode) {
          this.parentNode.insertBefore(elem, this.nextSibling);
        }
      });
    },
	//移除元素
    remove: function (selector, keepData /* Internal Use Only */ ) {
      var elem,
        elems = selector ? jQuery.filter(selector, this) : this,
        i = 0;

      for (;
        (elem = elems[i]) != null; i++) {

        if (!keepData && elem.nodeType === 1) {
          jQuery.cleanData(getAll(elem));
        }

        if (elem.parentNode) {
          if (keepData && jQuery.contains(elem.ownerDocument, elem)) {
            setGlobalEval(getAll(elem, "script"));
          }
          elem.parentNode.removeChild(elem);
        }
      }

      return this;
    },
	//也是移除元素
    empty: function () {
      var elem,
        i = 0;

      for (;
        (elem = this[i]) != null; i++) {
        // Remove element nodes and prevent memory leaks
        // 删除元素节点并防止内存泄漏
        if (elem.nodeType === 1) {
          jQuery.cleanData(getAll(elem, false));
        }

        // Remove any remaining nodes
        // 删除所有剩余节点
        while (elem.firstChild) {
          elem.removeChild(elem.firstChild);
        }

        // If this is a select, ensure that it displays empty (#12336)
        // 如果这是选择,请确保它显示为空(#12336)
        // Support: IE<9
        if (elem.options && jQuery.nodeName(elem, "select")) {
          elem.options.length = 0;
        }
      }

      return this;
    },
	//复制元素
    clone: function (dataAndEvents, deepDataAndEvents) {
      dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
      deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

      return this.map(function () {
        return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
      });
    },
	//设置内容
    html: function (value) {
      return access(this, function (value) {
        var elem = this[0] || {},
          i = 0,
          l = this.length;

        if (value === undefined) {
          return elem.nodeType === 1 ?
            elem.innerHTML.replace(rinlinejQuery, "") :
            undefined;
        }

        // See if we can take a shortcut and just use innerHTML
        // 看看我们是否可以采取快捷方式,只是使用内部HTML
        if (typeof value === "string" && !rnoInnerhtml.test(value) &&
          (support.htmlSerialize || !rnoshimcache.test(value)) &&
          (support.leadingWhitespace || !rleadingWhitespace.test(value)) &&
          !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {

          value = value.replace(rxhtmlTag, "<$1></$2>");

          try {
            for (; i < l; i++) {
              // Remove element nodes and prevent memory leaks
              // 删除元素节点并防止内存泄漏
              elem = this[i] || {};
              if (elem.nodeType === 1) {
                jQuery.cleanData(getAll(elem, false));
                elem.innerHTML = value;
              }
            }

            elem = 0;

            // If using innerHTML throws an exception, use the fallback method
            // 如果使用内部HTML引发异常,请使用回退方法
          } catch (e) {}
        }

        if (elem) {
          this.empty().append(value);
        }
      }, null, value, arguments.length);
    },
	//替换元素
    replaceWith: function () {
      var arg = arguments[0];

      // Make the changes, replacing each context element with the new content
      // 进行更改,将每个上下文元素替换为新内容
      this.domManip(arguments, function (elem) {
        arg = this.parentNode;

        jQuery.cleanData(getAll(this));

        if (arg) {
          arg.replaceChild(elem, this);
        }
      });

      // Force removal if there was no new content (e.g., from empty arguments)
      // 如果没有新内容(例如,从空参数删除)
      return arg && (arg.length || arg.nodeType) ? this : this.remove();
    },
	//删除元素
    detach: function (selector) {
      return this.remove(selector, true);
    },
  });

笔者资历尚浅,如有其他见解欢迎指点。
推荐阅读:
JS的设计模式——观察者设计模式

JS中遍历DOM树

四个问题彻底学会JS中“闭包”

jQuery选择器总结以及用法介绍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值