发现问题:

今天在写一个特别简单的jQuery代码的时候,发现了一个bug,当同时使用append和perpend时,代码中靠后的会将靠前的覆盖掉,具体如下:(jQuery版本为3.6.4)

<body>
    <ul>
        <li class="old">old</li>
    </ul>
    <script>
        $(function () {
            const New = $("<li>new</li>")
            $("ul").append(New) // 向子代最后插入
            $("ul").prepend(New) // 向子代最前插入
        }) 
    </script>
</body>

运行结果为

jquery 层级比较深 怎么根据当前层级找到快顶级的层级 jquery同级append_父节点

 后面经验证,单独使用时没有任何问题,但是同时使用就是会出现问题,即后面的会覆盖掉前面的

<body>
    <ul>
        <li class="old">old</li>
    </ul>
    <script>
        $(function () {
            const New = $("<li>new</li>")
            //反转一下代码顺序
            $("ul").prepend(New) // 向子代最前插入
            $("ul").append(New) // 向子代最后插入
        }) 
    </script>
</body>

结果如下:

jquery 层级比较深 怎么根据当前层级找到快顶级的层级 jquery同级append_jQuery_02

那么到底是什么问题导致的呢,去翻了翻jQuery源文件发现,append和prepend是用如下代码实现的:

append: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.appendChild( elem );
			}
		} );
	},

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 );
			}
		} );
	},

看了看,感觉也没有什么会引起冲突的地方,都是一些基础节点操作,无从下手怎么办,删代码!对jQuery源代码进行删删改改发现,不管怎么改都会冲突。最后突然想到,有没有可能是appendChild和insertBefore这两个源代码就冲突呢?说干就干:

<body>
    <ul>
        <li class="old">old</li>
    </ul>
    <script>
        const New = document.createElement('li')
        New.innerText = "new"
        const ul = document.querySelector('ul')
        const old = document.querySelector('.old')
        ul.appendChild(New)//向子代最后插入
        ul.insertBefore(New, old)//向子代中的old前插入,相当于向子代最前插入
    </script>
</body>

运行结果:

jquery 层级比较深 怎么根据当前层级找到快顶级的层级 jquery同级append_javascript_03

 哈哈,不出所料,问题出在根源上了,原生js的问题,那...到底是什么导致的这个原生js问题呢?

解决问题:

跟据mdn官方文档可知:

Node.appendChild() 方法将一个节点附加到指定父节点的子节点列表的末尾处。如果将被插入的节点已经存在于当前文档的文档树中,那么 appendChild() 只会将它从原先的位置移动到新的位置(不需要事先移除要移动的节点)。

也就是说,这个新创建的节点,由于保存到了New中,地址相同,在同一文档中就会被当作是同一节点,JS规定:同一节点不可能被插入到文档的不同位置。

当然了,官方也给出了相应的解决办法:

若要保留已在文档中的节点,可以先使用 Node.cloneNode() 方法来为它创建一个副本,再将副本附加到目标父节点下。请注意,用 cloneNode 制作的副本不会自动保持同步。

<body>
    <ul>
        <li class="old">old</li>
    </ul>
    <script>
        const New1 = document.createElement('li')
        New1.innerText = "new"
        const New2 = New1.cloneNode()
        New2.innerText = "new" // cloneNode()只会复制节点,不会复制节点内的内容,需重新给节点赋值
        const ul = document.querySelector('ul')
        const old = document.querySelector('.old')
        ul.insertBefore(New1, old)//向子代中的old前插入,相当于向子代最前插入
        ul.append(New2)//向子代最后插入
    </script>
</body>
<ul>
        <li class="old">old</li>
    </ul>
    <script>
        $(function () {
            const New1 = $("<li>new</li>")
            const New2 = New1.clone()
            $("ul").prepend(New1) // 向子代最前插入
            $("ul").append(New2) // 向子代最后插入
        }) 
    </script>

这样就解决了这个问题:

运行结果如下:

jquery 层级比较深 怎么根据当前层级找到快顶级的层级 jquery同级append_前端_04

当然,除了使用clone()方法外,还有一种方法:

<body>
    <ul>
        <li class="old">old</li>
    </ul>
    <script>
        $(function () {
            $("ul").prepend($("<li>new</li>")) // 向子代最前插入
            $("ul").append($("<li>new</li>")) // 向子代最后插入
        }) 
    </script>
</body>

jquery 层级比较深 怎么根据当前层级找到快顶级的层级 jquery同级append_父节点_05

 照样可以实现这个功能

同理,也可以解决jQuery中before和after冲突问题

至此,这个问题已经解决完成

有什么问题可以评论区讨论

下次见啦~