【问题标题】:JavaScript to sort DOM elements by some comparator, without jQueryJavaScript 通过一些比较器对 DOM 元素进行排序,没有 jQuery
【发布时间】:2015-06-25 17:09:17
【问题描述】:

想象一些 DOM 元素:

<ul id="list">
  <li data-index="3">Baz</li>
  <li data-index="1">Foo</li>
  <li data-index="2">Bar</li>
</ul>

如何在不使用 jQuery 的情况下使用 JavaScript 对这些元素进行排序?

类似于:

document.getElementById('list').sort(function(li) { return li.dataset.index; });

【问题讨论】:

  • 尝试在网上搜索这个问题,除了一些 jQuery 的东西之外,你会发现没有任何内容可以涵盖这个问题。对我来说,这似乎是一个完全合理的问题。如果您有不同的感觉,请解释原因。
  • 将对li元素的引用放入一个数组(或将NodeList转换为一个),排序,然后按数组顺序将元素插入DOM……完成。
  • @CBroe,这涉及大量 DOM 流失,这对性能不利,尤其是在列表已经大部分排序的情况下。理想情况下,我想就地进行排序。
  • “就地”排序可能会更慢,您需要多次附加相同的元素。顺便提一句。我没有投反对票,但也许缺乏真正的尝试来解决这个问题导致投反对票。

标签: javascript dom dom-manipulation


【解决方案1】:

您应该使用弹性盒的排序功能。这将允许重新排序元素,而无需在 DOM 中移动它们。这涉及设置 CSS order 属性。

更多详情请见https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes。

【讨论】:

  • 好主意,但遗憾的是 attr() 目前仅适用于 content 属性和字符串。未来order: attr(data-index integer)会很棒。
  • 不错!订购应该是一个演示问题。对于我所针对的浏览器(私有、受控部署)的支持似乎还可以,但可能还不适合所有人:caniuse.com/#search=flexbox
  • @Oriol 不明白您的担忧。在初始代码中,您可以只使用style='order: 1; ' 而不是data-index='1'。然后,在排序代码中,可以根据结果设置elt.style.order。
  • @torazaburo 问题是我觉得内联样式很难看 :)
  • @Oriol(使用 CSS 预处理器)您可以轻松创建一些实用程序类,然后应用它们。
【解决方案2】:

前段时间我写了这个:

function sortChildren(wrap, f, isNum) {
    var l = wrap.children.length,
        arr = new Array(l);
    for(var i=0; i<l; ++i)
        arr[i] = [f(wrap.children[i]), wrap.children[i]];
    arr.sort(isNum
        ? function(a,b){ return a[0]-b[0]; }
        : function(a,b){ return a[0]<b[0] ? -1 : a[0]>b[0] ? 1 : 0; }
    );
    var par = wrap.parentNode,
        ref = wrap.nextSibling;
    par.removeChild(wrap);
    for(var i=0; i<l; ++i) wrap.appendChild(arr[i][1]);
    par.insertBefore(wrap, ref);
}

基本上:

  1. 首先创建一个数组来存储元素及其对应的比较器函数返回的值。

    我们也可以在排序的时候运行这个函数,但是由于 DOM 交互很慢,这样我们就可以确保每个元素只运行一次函数。

  2. 然后,我们使用原生 sort 对其进行排序。

    如果isNum 参数是真的,我们使用一个排序函数来比较数字。如果比较器函数返回字符串但您想以数字方式而不是字典方式进行比较,则需要这样做。

  3. 现在,我们从 DOM 中移除包装元素。这种方式重新排序孩子会更便宜(例如避免重新付款)。

  4. 最后,我们重新排序孩子,并在其位置插入包装器。

像这样运行它

sortChildren(
    document.getElementById('list'),
    function(li) { return li.dataset.index; },
    true
);

或

sortChildren(
    document.getElementById('list'),
    function(li) { return +li.dataset.index; }
);

Demo

【讨论】:

    【解决方案3】:
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset= "utf-8">
    <title>sort list</title>
    </head>
    <body>
    <strong>Double click the list to sort by data-index</strong>
    <ul id= "list">
    <li data-index= "3">Baz</li>
    <li data-index= "1">Foo</li>
    <li data-index= "2">Bar</li>
    </ul>
    <script>
    
    document.body.ondblclick=function(){
        var A=[], pa= document.getElementById('list');
        var itemz= pa.getElementsByTagName('li');
    
        A.slice.call(itemz).sort(function(a, b){
            return a.getAttribute('data-index')-b.getAttribute('data-index');
        }).forEach(function(next){
                pa.appendChild(next);
        });
    }
    
    </script>
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-25
      • 1970-01-01
      • 2014-04-26
      相关资源
      最近更新 更多