相关文章推荐
慷慨的柿子  ·  用PHP封装一个强大且通用的cURL方法 ...·  7 月前    · 
坚强的大熊猫  ·  我在写一段优化算法的代码,报了TypeErr ...·  8 月前    · 
帅气的斑马  ·  Django - K8sCat的个人空间 ...·  9 月前    · 
无邪的蚂蚁  ·  浅析JS中base64和图片互相转换(附代码 ...·  1 年前    · 
英俊的大葱  ·  从 jsonpath 和 xpath 到 ...·  1 年前    · 
Code  ›  jQuery源码解析之after()/insertAfter()/before()/prepend()的实现开发者社区
https://cloud.tencent.com/developer/article/1965030
想旅行的熊猫
11 月前
进击的小进进

jQuery源码解析之after()/insertAfter()/before()/prepend()的实现

前往小程序,Get 更优 阅读体验!
立即前往
腾讯云
开发者社区
文档 建议反馈 控制台
首页
学习
活动
专区
工具
TVP
最新优惠活动
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
进击的小进进
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
社区首页 > 专栏 > jQuery源码解析之after()/insertAfter()/before()/prepend()的实现

jQuery源码解析之after()/insertAfter()/before()/prepend()的实现

作者头像
进击的小进进
发布 于 2022-03-28 14:49:00
994 0
发布 于 2022-03-28 14:49:00
举报
文章被收录于专栏: 前端干货和生活感悟 前端干货和生活感悟

前言: 跟 当我调用了 $() .append()后,jQuery内部发生了什么? 一样,after() / insertAfteer() / before() / prepend(),都会经过 domManip() 和 buildFragment() 的洗礼,最后调用原生JS的方法来实现。

所以,本文只讲述 jQuery 中最后对 after() / insertAfter() / before() / prepend() 处理的相关代码。

想了解 domManip() 和 buildFragment() 的,请看 当我调用了 $() .append()后,jQuery内部发生了什么?


一、示例HTML

代码语言: javascript
复制
<script src="jQuery.js"></script>
<div id="divTwo">
  <p>这是divTwo</p>
<div id="divOne">
  <p>这是divOne</p>
<script>
  let divOne = document.querySelector("#divOne")
  let divTwo = document.querySelector("#divTwo")
</script>

二、after() 作用: 在被选元素 (外部)后 插入 HTML 元素

注意: 会移动已有节点到指定位置

简单实现:

代码语言: javascript
复制
let divOne = document.querySelector("#divOne")
let divTwo = document.querySelector("#divTwo")
//在divOne的第一个child之前插入divTwo
divOne.parentNode.insertBefore(divTwo, divOne.nextSibling)
//上面的等价于
$("#divOne").after($("#divTwo"))

源码:

代码语言: javascript
复制
//在被选元素之后插入指定的内容(不是内部)
    //会移动已有节点到指定位置
    //http://www.runoob.com/jquery/html-after.html
    //源码6225行
    after: function() {
      return domManip( this, arguments, function( elem ) {
        if ( this.parentNode ) {
          //a.insertBefore(elem, a.firstElementChild )
          //在a的第一个child之前插入elem
          //由父节点调用insertBefore,在目标节点的后一节点 的前面插入新节点
          this.parentNode.insertBefore( elem, this.nextSibling );
可以看到,在经历了 domManip 的洗礼后,返回符合规范的 elem 即待插入元素,
然后 this 表示 selector ,
在 this 的父节点存在的情况下调用 this.parentNode.insertBefore( elem, this.nextSibling ) 完成 after() 操作。

三、insertAfter() 作用:在被选元素(外部)后 插入 HTML 元素

代码语言:javascript
复制
$("#divTwo").insertAfter($("#divOne"))
//等价于
$("#divOne").after($("#divTwo"))

注意:和 after() 作用一样,只是调用的元素顺序相反

源码很有意思:

代码语言:javascript
复制
  //源码6340行
  jQuery.each( {
    // 在被选元素(内部)的结尾插入 HTML 元素
    appendTo: "append",
    // 在被选元素(内部)的开头插入 HTML 元素
    prependTo: "prepend",
    // 在被选元素(外部)前插入 HTML 元素
    insertBefore: "before",
    // 在被选元素(外部)后插入 HTML 元素
    insertAfter: "after",
    // 把被选元素(整个)替换为新的 HTML 元素
    replaceAll: "replaceWith"
    //key,value
    function( name, original ) {
    //insertAfter
    jQuery.fn[ name ] = function( selector ) {
      var elems,
        ret = [],
        insert = jQuery( selector ),
        last = insert.length - 1,
        i = 0;
      //根据selector的个数来循环
      for ( ; i <= last; i++ ) {
        //如果有多个选择器,就将待插入的节点深复制
        elems = i === last ? this : this.clone( true );
        //$().after(elem)
        jQuery( insert[ i ] )[ original ]( elems );
        // Support: Android <=4.0 only, PhantomJS 1 only
        // .get() because push.apply(_, arraylike) throws on ancient WebKit
        //push:array.push()
        //ret.push(elems.get()) 作用就是将待插入的DOM节点依次放进ret数组中
        //$().get():获取selector的DOM元素
        push.apply( ret, elems.get() );
      //$().pushStack将一个DOM集合压入jQuery栈,并返回DOM集合的jQuery对象,用于链式调用
      return this.pushStack( ret );

解析:insertAfter() 是如何偷懒,调用 after()的?

(1)调用 $.each( { key: xxx, value: yyy } , function( key, value ){ } ) 依次定义 appendTo() / prependTo() / insertBefore() / insertAfter() / replaceAll()

(2)将 selector 和 待插入元素 调换位置

代码语言:javascript
复制
let insert = jQuery( selector )
//$(xxx).after(yyy)
 jQuery( insert[ i ] )[ original ]( elems )

(3)根据 selector 的个数作循环,深复制待插入的节点,并依次调用 after() 方法

代码语言:javascript
复制
   for ( ; i <= last; i++ ) {
        //如果有多个选择器,就将待插入的节点深复制
        elems = i === last ? this : this.clone( true );
        //$().after(elem)
        jQuery( insert[ i ] )[ original ]( elems );
        push.apply( ret, elems.get() );

(4)最后,调用 $().pushStack 依次返回处理后 新的 jQuery对象,用于链式调用

代码语言:javascript
复制
return this.pushStack( ret );

注意:appendTo() / prependTo() / insertBefore() / replaceAll() 实现方法类似,就不一一解释了。


四、prepend() 作用:在被选元素(内部)的开头插入 HTML 元素

源码:

代码语言:javascript
复制
    //在被选元素内部的开头插入指定内容
    prepend: function() {
      return domManip( this, arguments, function( elem ) {
        if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
          var target = manipulationTarget( this, elem );
          target.insertBefore( elem, target.firstChild );

解析:

代码语言:javascript
复制
//=========prepend()===========
  $("#divTwo").prepend($("#divOne"))
  //上面的等价于
  divTwo.insertBefore( divOne, divTwo.firstChild )

prepend() 其实是调用了 原生 insertBefore() 方法,也就是在 divTwo 内部的第一个子节点前插入 divOne


五、before() 作用:在被选元素(外部)之前插入 HTML 元素

源码:

代码语言:javascript
复制
    //在被选元素之前插入指定的内容
    //源码6218行
    before: function() {
      return domManip( this, arguments, function( elem ) {
        if ( this.parentNode ) {
          this.parentNode.insertBefore( elem, this );
 
推荐文章
慷慨的柿子  ·  用PHP封装一个强大且通用的cURL方法 - 小松聊PHP进阶 - 博客园
7 月前
坚强的大熊猫  ·  我在写一段优化算法的代码,报了TypeError: cannot pickle 'PyCapsule' object - CSDN文库
8 月前
帅气的斑马  ·  Django - K8sCat的个人空间 - OSCHINA - 中文开源技术交流社区
9 月前
无邪的蚂蚁  ·  浅析JS中base64和图片互相转换(附代码)_51CTO博客_js 图片转base64
1 年前
英俊的大葱  ·  从 jsonpath 和 xpath 到 SPL-腾讯云开发者社区-腾讯云
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号