如何修改原生JS表格排序函数以支持dd/mm/yyyy日期排序
Hey there! I get it—your current table sort works great for regular text and numbers, but it’s totally messing up dates in dd/mm/yyyy format because it’s just comparing strings alphabetically instead of chronologically. Let’s fix this without any jQuery, and even add some extra polish for numeric columns while we’re at it!
The Root Problem
When you compare date strings like "25/11/2020" and "20/09/2020" as plain text, "25..." gets treated as "larger" than "20..." because the second character 5 is bigger than 0—which is wrong for actual date order. We need to convert these strings into proper JavaScript Date objects so we can compare their real chronological values.
Modified Sort Function with Date Handling
Here’s the updated function that handles dates, numbers, and text correctly:
function sortMaoDeObraPrintItemList(n) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById("MaoDeObraNaoFaturadasPerClientControlPanelPrint"); switching = true; dir = "asc"; // Helper to convert dd/mm/yyyy strings to valid Date objects function convertDMYtoDate(dateStr) { const parts = dateStr.split('/'); // Validate the date format before converting if (parts.length === 3 && !isNaN(parts[0]) && !isNaN(parts[1]) && !isNaN(parts[2])) { // Months are 0-indexed in JS, so subtract 1 from the month value return new Date(parts[2], parts[1] - 1, parts[0]); } return null; // Not a valid date—fall back to other comparison methods } while (switching) { switching = false; rows = table.rows; for (i = 1; i < (rows.length - 1); i++) { shouldSwitch = false; x = rows[i].getElementsByTagName("TD")[n]; y = rows[i + 1].getElementsByTagName("TD")[n]; // Use textContent instead of innerHTML for cleaner raw text extraction let xVal = x.textContent.trim(); let yVal = y.textContent.trim(); // Try converting to dates first let xDate = convertDMYtoDate(xVal); let yDate = convertDMYtoDate(yVal); if (xDate && yDate) { // Compare date timestamps for proper chronological order if (dir === "asc") { shouldSwitch = xDate > yDate; } else { shouldSwitch = xDate < yDate; } } else { // Check if values are numeric (handle commas for decimal separators) let xNum = parseFloat(xVal.replace(',', '.')); let yNum = parseFloat(yVal.replace(',', '.')); if (!isNaN(xNum) && !isNaN(yNum)) { // Numeric comparison for IDs, ages, amounts if (dir === "asc") { shouldSwitch = xNum > yNum; } else { shouldSwitch = xNum < yNum; } } else { // Fall back to case-insensitive string comparison if (dir === "asc") { shouldSwitch = xVal.toLowerCase() > yVal.toLowerCase(); } else { shouldSwitch = xVal.toLowerCase() < yVal.toLowerCase(); } } } if (shouldSwitch) break; } if (shouldSwitch) { rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; switchcount ++; } else { // If no switches happened, reverse direction and try again if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } }
Key Improvements Explained
- Date Conversion: The
convertDMYtoDatefunction splits the date string, adjusts the month (since JS dates use 0-indexed months), and validates the input to avoid invalid dates. - Smart Comparison: The function first checks if values are valid dates, then checks if they’re numbers (handling comma decimal separators), and falls back to text comparison if neither applies.
- Cleaner Text Extraction: Using
textContentinstead ofinnerHTMLavoids issues with hidden HTML elements and gives us raw, unformatted text.
Your Updated Table (No Changes Needed!)
You can keep your existing table structure—just use the new function above:
<table id='MaoDeObraNaoFaturadasPerClientControlPanelPrint' border='0'> <tr> <th onclick='sortMaoDeObraPrintItemList(0)'>ID</th> <th onclick='sortMaoDeObraPrintItemList(1)'>DATE</th> <th onclick='sortMaoDeObraPrintItemList(2)'>FUNCIONARIO</th> <th onclick='sortMaoDeObraPrintItemList(3)'>AGE</th> <th onclick='sortMaoDeObraPrintItemList(4)'>DESCRICAO</th> <th onclick='sortMaoDeObraPrintItemList(5)'>AMOUNT</th> </tr> <tr> <td>106</td> <td>25/11/2020</td> <td>John</td> <td>33</td> <td>Red</td> <td>100,00</td> </tr> <tr> <td>102</td> <td>20/09/2020</td> <td>Maria</td> <td>34</td> <td>white</td> <td>200,00</td> </tr> <tr> <td>101</td> <td>29/12/2020</td> <td>Roger</td> <td>20</td> <td>blue</td> <td>50,00</td> </tr> <tr> <td>107</td> <td>28/01/2020</td> <td>Robert</td> <td>10</td> <td>Green</td> <td>1050,00</td> </tr> </table>
Now when you click the DATE header, your dates will sort correctly chronologically (ascending order will show 28/01/2020 first, then 20/09/2020, etc.), and all other columns will work better too—numeric columns like ID and AMOUNT will sort by actual value instead of string order.
内容的提问来源于stack exchange,提问作者user2916405

