【问题标题】:Reorder html elements in dom对dom中的html元素重新排序
【发布时间】:2016-01-08 20:14:03
【问题描述】:

我有一个元素列表:

<div class="wrapper">
    <div class="abc"></div>
    <div class="abc"></div>
    <div class="abc"></div>
</div>

我有一个代表新订单的数组或数字:

var arr = [2,1,0];

我想将这些 abc div 重新定位到父包装器内的新位置。

重要的是 abc div 附有事件和数据,这需要保留!

我想出了这个,它似乎按预期工作:

var wrapper = $('.wrapper'), items = wrapper.children('div.abc');

var orderedItems = $.map(arr, function(value) {
    return $(items).clone(true,true).get(value);
});
wrapper.empty().html(orderedItems);

我想确保这是正确的方法。

如果可能的话,我也可以使用 javascript 解决方案。

【问题讨论】:

  • 郑重声明,jQuery 是一个用 Javascript 编写的框架,这意味着你所拥有的是一个 Javascript 解决方案
  • 如果它工作正常,那么它工作!您还可以考虑使用带有 flexbox 的 CSS 和 order 重新排序:w3schools.com/cssref/css3_pr_order.asp

标签: javascript jquery dom


【解决方案1】:

如果您想要纯 Javascript 解决方案(不涉及 jQuery)

var arr = [2,1,0];
var wrapper = document.getElementsByClassName("wrapper");
var items = wrapper[0].children;
var elements = document.createDocumentFragment();

arr.forEach(function(idx) {
    elements.appendChild(items[idx].cloneNode(true));
});

wrapper[0].innerHTML = null;
wrapper[0].appendChild(elements);

对我之前的答案进行了一些改进。小提琴:https://jsfiddle.net/jltorresm/1ukhzbg2/2/

【讨论】:

  • 请,请使用文档碎片随身携带一批物品
  • 你说得对,Thomas,将我的答案改为使用文档片段
  • 但是这样做我会丢失所有附加到元素的事件监听器,cloneNode不会携带任何监听器
  • 当您将documentFragment 附加到文档时,它本身是否显示为父元素?
【解决方案2】:

请记住,当您添加一个已经在 DOM 中的元素时,该元素将被移动,而不是复制。

CodePen

let wrapper=document.querySelector(".wrapper");
let children=wrapper.children;
let newOrder=[3,2,1,0];
//it means that the first element you want it to be the four element
//The second element you want it to be the third
//the third element you want it to be the second
//the four element you want it to be the first
for(let i=0;i<newOrder.length;i++){
  for(let j=0;j<newOrder.length;j++){
    if(i==newOrder[j]){
      wrapper.appendChild(children[j]);
      break;
    }
  }
}
<div class="wrapper">
  <div>a</div>
  <div>b</div>
  <div>c</div>
  <div>d</div>
</div>

【讨论】:

    【解决方案3】:

    无需复制所有项目..两次

    var wrapper = $('.wrapper'), 
        items = wrapper.children('.abc'),
        arr = [2,1,0];
    
    //items.detach(); if arr doesn't reuse all items
    wrapper.append( $.map(arr, function(v){ return items[v] }) );
    

    【讨论】:

    • 我不确定我理解你所说的复制两次是什么意思。我已经尝试过您的示例,这不会复制我在原始帖子中提到的事件。 (这就是我使用 jquery clone 的原因)。我错过了什么?
    • 请显示 aou 使用的确切代码并解释哪些特别不起作用。我的代码中的要点是,它以正确的顺序创建实际 DOM 节点的中间数组,并将它们附加到包装器中。通过将 DOM 节点添加到(新)父节点,它首先从它所在的节点中删除,然后添加到新节点。没有克隆节点,没有引用/事件/属性/任何更改,只有 DOM 树中的位置。
    • 通过复制两次我的意思是:首先创建当前节点的克隆,然后 afaik $.html() 将其转换为字符串表示并再次解析此字符串表示(节点再次基本上都是克隆的)。
    【解决方案4】:

    我知道这是一个老问题,但谷歌将我引向了它。 flexbox (css) 上有一个名为“order”的子属性,允许您选择元素显示的顺序。可以使用 javascript 来更改此子属性并重新排序显示的元素。

    https://www.w3schools.com/cssref/css3_pr_order.asp

    编辑 1 - 代码示例:

    <style>
     .wrapper {
       display: flex;
       flex-flow: column;
     }
    </style>
    
    <div class="wrapper">
      <div class="abc">One</div>
      <div class="abc">Tow</div>
      <div class="abc">Three</div>
    </div>
    <button id="reorder" type="button">Reorder</button>
    <button id="unreorder" type="button">Unreorder</button>
    
    <script>
    var reorderButton = document.querySelector('#reorder');
    var unreorderButton = document.querySelector('#unreorder');
    var abcDivs = document.querySelectorAll('.abc');
    var newOrder = [2, 1, 0];
    
    reorderButton.addEventListener('click', function() {
      abcDivs.forEach(function(element, index) {
        element.style.order = newOrder[index];
      });
    });
    unreorderButton.addEventListener('click', function() {
      abcDivs.forEach(function(element, index) {
        element.style.order = null;
      });
    });
    </script>
    

    【讨论】:

    • 除了 w3schools 链接之外,最好提供一个适用于该问题的示例。
    • 这是一个很棒的简单建议,可以在您可以使用 flexbox 的情况下执行此操作。谢谢!
    • 好建议
    • 好主意。非常感谢您的提示
    • 规范和MDN 明确建议不要使用这种技巧(除非重新排序是纯视觉的并且没有语义):“如果您使用反向值,或者以其他方式重新排序您的项目,您应该考虑是否真的需要更改源中的逻辑顺序。规范继续警告不要使用重新排序来解决源中的问题”
    【解决方案5】:

    这个解决方案对我来说效果更好,我们构建一个元素数组 ([...wrapper.children]) 然后我们使用基于模型 ([5,4,3,2,1,0]) 的 .sort 然后我们使用追加子。由于元素与原始元素相同,因此事件侦听器仍然可以正常工作。代码如下:

    //this is just to add event listeners
    [...document.getElementsByClassName("abc")].forEach(e =>
      e.addEventListener("click", ev => console.log(ev.target.innerText))
    );
    
    var wrapper = document.getElementsByClassName("wrapper")[0];
    var items = [...wrapper.children];
    
    const newOrder = [5,4,3,2,1,0]
    
    items.sort((a, b)=>newOrder.indexOf(items.indexOf(a)) - newOrder.indexOf(items.indexOf(b)));
    
    items.forEach(it=>wrapper.appendChild(it));
    <div class="wrapper">
      <div class="abc">0</div>
      <div class="abc">1</div>
      <div class="abc">2</div>
      <div class="abc">3</div>
      <div class="abc">4</div>
      <div class="abc">5</div>
    </div>

    如您所见,如果您单击 0、1 等,事件侦听器将起作用。

    【讨论】:

      猜你喜欢
      • 2020-08-16
      • 2013-09-11
      • 2020-06-29
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      相关资源
      最近更新 更多