2008-11-12 41 views
41

Nếu tôi có một danh sách như thế này:Cách dễ nhất để sắp xếp các nút DOM?

<ul id="mylist"> 
    <li id="list-item1">text 1</li> 
    <li id="list-item2">text 2</li> 
    <li id="list-item3">text 3</li> 
    <li id="list-item4">text 4</li> 
</ul> 

cách dễ nhất để sắp xếp lại các nút DOM để sở thích của tôi là gì? (Điều này cần xảy ra tự động khi tải trang, tùy chọn thứ tự danh sách được lấy từ cookie)

Ví dụ:

<ul id="mylist"> 
    <li id="list-item3">text 3</li> 
    <li id="list-item4">text 4</li> 
    <li id="list-item2">text 2</li> 
    <li id="list-item1">text 1</li> 
</ul> 
+0

Tôi không chắc chắn nếu điều này sẽ giúp bạn, nhưng nếu bạn đang sử dụng một công nghệ phía máy chủ (như PHP) về vấn đề này trang, sau đó nó cũng nên có quyền truy cập vào các tập tin cookie. trong PHP, nó nằm trong mảng $ _COOKIE toàn cầu. – nickf

Trả lời

62

Mặc dù có thể dễ dàng hơn để thực hiện việc này bằng Thư viện JS, đây là giải pháp hoạt động bằng cách sử dụng vanilla js.

var list = document.getElementById('mylist'); 

var items = list.childNodes; 
var itemsArr = []; 
for (var i in items) { 
    if (items[i].nodeType == 1) { // get rid of the whitespace text nodes 
     itemsArr.push(items[i]); 
    } 
} 

itemsArr.sort(function(a, b) { 
    return a.innerHTML == b.innerHTML 
      ? 0 
      : (a.innerHTML > b.innerHTML ? 1 : -1); 
}); 

for (i = 0; i < itemsArr.length; ++i) { 
    list.appendChild(itemsArr[i]); 
} 
+0

Cảm ơn giải pháp của bạn NickF, tôi sẽ điều chỉnh nó một chút vì tôi đang sử dụng jQuery nhưng tôi nghĩ tôi có ý tưởng làm thế nào để làm điều đó ngay bây giờ, cảm ơn! :) – James

+27

Bằng cách sử dụng 'list.children' thay vì' list.childNodes', bạn có thể tránh kiểm tra các nút văn bản. –

+0

Khi tôi lần đầu tiên đọc câu trả lời này, tôi nghĩ vani js? Tại sao [vanilla.js] (http://vanilla-js.com/) được yêu cầu ở đây? : ^) – zipzit

14

Bạn có thể thấy rằng việc sắp xếp các nút DOM không hoạt động tốt. Một cách tiếp cận khác sẽ có trong javascript của bạn một mảng đại diện cho dữ liệu sẽ đi vào các nút DOM, sắp xếp dữ liệu đó và sau đó tạo lại div chứa các nút DOM.

Có thể bạn không có nhiều nút để sắp xếp, vì vậy sẽ không thành vấn đề. Kinh nghiệm của tôi dựa trên việc cố gắng sắp xếp các bảng HTML bằng cách thao tác DOM, bao gồm các bảng với hàng trăm hàng và một vài chục cột.

9

Nếu bạn đã sử dụng jQuery, tôi khuyên bạn nên tinysort: http://tinysort.sjeiti.com/

$("li").tsort({order:"asc"}); 
$("li").tsort({order:"desc"}); 
+2

Tinysort chậm hơn nhiều lần so với 13 dòng mã, dựa trên kết quả phân loại jquery sắp xếp và thêm nó trở lại - http: // jsperf.com/attr-vs-getattribute/12 –

+0

TinySort từng là một plugin jQuery nhưng được viết lại để loại bỏ sự phụ thuộc của jQuery. Nó bây giờ là nhỏ hơn và nhanh hơn –

1

mà không phân tích quá nhiều nếu điều này mang lại bất cứ điều gì mới để bàn, tôi thường sử dụng này:

function forEach(ar, func){ if(ar){for(var i=ar.length; i--;){ func(ar[i], i); }} } 
function removeElement(node){ return node.parentNode.removeChild(node); } 
function insertBefore(ref){ return function(node){ return ref.parentNode.insertBefore(node, ref); }; } 

function sort(items, greater){ 
    var marker = insertBefore(items[0])(document.createElement("div")); //in case there is stuff before/after the sortees 
    forEach(items, removeElement); 
    items.sort(greater); 
    items.reverse(); //because the last will be first when reappending 
    forEach(items, insertBefore(marker)); 
    removeElement(marker); 
} 

trong đó mục là một mảng trẻ em cùng cha/mẹ. chúng tôi loại bỏ bắt đầu với phần cuối cùng và nối thêm bắt đầu với phần đầu tiên để tránh nhấp nháy ở phần trên cùng có thể trên màn hình. tôi thường nhận mảng mục của tôi như thế này:

forEachSnapshot(document.evaluate(..., 6, null), function(n, i){ items[i] = n; }); 
13

Nhìn thấy nó trong hành động: http://jsfiddle.net/stefek99/y7JyT/

jQuery.fn.sortDomElements = (function() { 
     return function(comparator) { 
      return Array.prototype.sort.call(this, comparator).each(function(i) { 
        this.parentNode.appendChild(this); 
      }); 
     }; 
    })(); 

ngắn gọn

+0

Tốt đẹp! Tôi cũng thích những thứ khác, do đó, dựa trên đó, tôi đã đưa ra một [hàm jQuery rất đơn giản] (http://jsfiddle.net/mindplay/H2mrp/) cho phép bạn cung cấp hàm gọi lại tính giá trị để sắp xếp bởi. (Tôi đã đưa ra hai ví dụ: phân loại danh sách theo thứ tự bảng chữ cái và sắp xếp bảng theo giá trị số trong cột đầu tiên - cả về cơ bản một lớp lót.) –

+0

Tôi biết đây là một bài đăng cũ, nhưng tôi có thể hỏi, lợi ích của sử dụng một hàm tự thực thi trả về hàm sortDomElements? Nó sẽ không được thêm terse để nói jQuery.fn.sortDomElements = chức năng (comparitor) ...? như thế này http://jsfiddle.net/y7JyT/77/ – Julian

5

phiên bản của tôi, hy vọng sẽ có ích cho người khác:

var p = document.getElementById('mylist'); 
Array.prototype.slice.call(p.children) 
    .map(function (x) { return p.removeChild(x); }) 
    .sort(function (x, y) { return /* sort logic */; }) 
    .forEach(function (x) { p.appendChild(x); }); 
+0

Bạn có ý nghĩa gì '/ * sắp xếp logic * /'? :/Các mã có vẻ tốt, nhưng logic sắp xếp của tôi là một chút yếu –

+1

Nó có nghĩa là bạn nên đặt logic sắp xếp của bạn ở đó, có một cái nhìn tại https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/ Global_Objects/Array/sắp xếp nó về cơ bản giống nhau, chỉ x và y là các nút DOM. –

2

Đây là một hàm ES6 để sắp xếp các nút DOM tại chỗ:

const sortChildren = ({ container, childSelector, getScore }) => { 
    const items = [...container.querySelectorAll(childSelector)]; 

    items 
    .sort((a, b) => getScore(b) - getScore(a)) 
    .forEach(item => container.appendChild(item)); 
}; 

Đây là cách bạn sẽ sử dụng nó để sắp xếp Untapped user reviews by score:

sortChildren({ 
    container: document.querySelector("#main-stream"), 
    childSelector: ".item", 
    getScore: item => { 
    const rating = item.querySelector(".rating"); 
    if (!rating) return 0; 
    const scoreString = [...rating.classList].find(c => /r\d+/.test(c)); 
    const score = parseInt(scoreString.slice(1)); 
    return score; 
    } 
}); 
Các vấn đề liên quan