【问题标题】:Weird order in jQuery collection filled with DOM elements and virtual elementsjQuery 集合中的奇怪顺序充满了 DOM 元素和虚拟元素
【发布时间】:2013-01-01 22:08:45
【问题描述】:

我正在编写自己的 jQuery 插件,其中我引用了一些现有节点,并创建了一些在 DOM 树中不存在的新 jQ 节点(它们没有附加)。我正在使用.add() 方法将每个元素添加到新集合中。

发生的情况是,这个集合的顺序看起来很奇怪(我在那里找不到任何逻辑模式)。文档中的以下注释可能是原因:

从 jQuery 1.4 开始,来自 .add() 的结果将始终按文档顺序返回(而不是简单的串联)。

考虑以下示例。

HTML

<body>
    <a id="existing1"></a><a id="existing2"></a>
</body>

JS

<script type="text/javascript">

    function addToColl(selector) {
        coll = coll.add(selector);
        var n = $(selector).get(0).id.match(/\d+/)[0];
        for (var i = 0; i < 4; i++) {
            var a = $('<a>',{id:'virtual'+n+'_'+i});
            coll = coll.add(a);
        }
    }

    $(document).ready(function() {

        coll = $();

        addToColl('#existing1');
        // uncomment the following to see what's happening
        //addToColl('#existing2');

        $.each(coll,function(idx,elm) {
            console.log(elm.id);
        });

    });

</script>

输出:

现有1
虚拟1_0
虚拟1_1
虚拟1_2
虚拟1_3

当你取消注释被注释的函数调用它输出

现有1
虚拟1_3
虚拟1_2
虚拟1_1
虚拟1_0
现有2
虚拟2_0
虚拟2_1
虚拟2_2
虚拟2_3

应该怎么做才能避免这种混乱?

------ [编辑] ------
由于add() 函数的意外行为,我最终使用原生Javascript 数组来收集元素(即使用push() 方法)。稍后,当我收集完元素后,我会将其转换为 jQuery 集合。

【问题讨论】:

  • 您是否尝试定义 coll = $([]);而不是 coll = $();
  • 文档中的注释仅适用于集合中的所有元素都在 DOM 中的情况。如果不是,则由于合并集合的方式,该顺序是不可预测的。
  • @YoniBaciu 不幸的是,它没有改变任何东西。
  • @Barmar 我认为,它在内部首先搜索 DOM 树中的元素,然后通过 for..in 循环或其他方式重新创建集合,这会改变元素的顺序。但有趣的是,这在任何地方都没有提及。
  • 我认为他们只是没有考虑一个集合可能同时包含连接和断开连接的元素。代码实际上并不是很小心。

标签: jquery jquery-selectors


【解决方案1】:

jQuery 中的代码如下所示:

    add: function( selector, context ) {
            var set = typeof selector === "string" ?
                            jQuery( selector, context ) :
                            jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
                    all = jQuery.merge( this.get(), set );

            return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
                    all :
                    jQuery.unique( all ) );
    },

因此,如果添加的集合的第一个元素或合并的集合断开连接,它只会返回合并的集合,无论jQuery.merge() 碰巧将它们放入其中。如果它们都连接,它会调用@987654323 @,将它们按 DOM 顺序排列。

但是,进行排序的比较函数是:

    function( a, b ) {
            if ( a === b ) {
                    hasDuplicate = true;
                    return 0;
            }

            return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
                    a.compareDocumentPosition :
                    a.compareDocumentPosition(b) & 4
            ) ? -1 : 1;
    }

这取决于浏览器在比较断开连接的元素与连接的元素或断开连接的元素时如何实现compareDocumentPosition()。我希望它在两种情况下都返回 DOCUMENT_POSITION_DISCONNECTED (1),但 Chrome 在后一种情况下返回 4 (DOCUMENT_POSITION_FOLLOWING),在第一种情况下返回其他位组合。

【讨论】:

  • 感谢您的洞察力。为了保持顺序正确,使用原生数组作为集合,然后使用符号 $(nativeArrayReference) 将其转换为 jQuery 集合似乎是唯一的方法。你怎么看?
  • 你没有描述你想要完成什么,所以很难说。但是,如果您希望它们保持添加它们的顺序,只需使用数组即可。
  • 稍后在代码中我在该集合上使用 jQuery 函数,因此我最终创建了一个原生数组,然后在数组修改结束时将其转换为 JQ 集合。很高兴知道add() 函数实际发生了什么。再次感谢:)
猜你喜欢
  • 2014-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多