表格排序功能优化及排序符号显示问题求助
表格排序功能优化方案
问题描述
参考社区内的表格排序代码及tbody行排序修复方案,实现了基本的表格排序功能,但在表头添加排序符号时遇到以下问题:
- 无按钮的Image列被点击后,会触发排序并变更data-dir属性,需禁用该列的排序交互;
- 已升序排序的列,再次点击时先重复升序排序,再切换为降序,需实现点击直接切换为降序;
- 自行添加的按钮data-dir重置与设置代码是否可进一步优化?
解决方案及代码优化
1. 禁用无按钮列的排序交互
在点击事件处理函数开头添加判断,若当前表头没有包含按钮,则直接退出函数,不执行排序逻辑:
if (!th.querySelector('button')) return;
2. 修复排序方向切换逻辑
原代码中排序方向的切换时机错误,导致重复排序。调整为先根据当前状态确定本次排序方向,排序完成后再更新状态:
- 先获取当前按钮的
data-dir属性,判断当前排序状态; - 确定本次排序方向:若当前是升序,则本次切换为降序,否则默认升序;
- 执行排序后更新按钮的
data-dir属性。
3. 优化data-dir重置逻辑
移除硬编码的按钮索引,改为通过表格选择器获取所有表头按钮,统一重置状态,提升代码灵活性:
// 重置当前表格所有表头按钮的排序状态 table.querySelectorAll('th button').forEach(btn => btn.setAttribute('data-dir', '')); // 设置当前点击按钮的排序状态 button.setAttribute('data-dir', asc ? 'asc' : 'desc');
修改后的完整代码
JavaScript
const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent; const comparer = (idx, asc) => (a, b) => ((v1, v2) => v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2) )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx)); document.querySelectorAll('th').forEach(th => th.addEventListener('click', (e) => { // 无按钮的列直接退出 const button = th.querySelector('button'); if (!button) return; const table = th.closest('table'); const tbody = table.querySelector('tbody'); const thIndex = Array.from(th.parentNode.children).indexOf(th); const currentDir = button.getAttribute('data-dir'); // 正确确定本次排序方向 const asc = currentDir !== 'asc'; // 执行排序 Array.from(tbody.querySelectorAll('tr')) .sort(comparer(thIndex, asc)) .forEach(tr => tbody.appendChild(tr)); // 优化后的状态重置与设置 table.querySelectorAll('th button').forEach(btn => btn.setAttribute('data-dir', '')); button.setAttribute('data-dir', asc ? 'asc' : 'desc'); }));
CSS
table, th, td { border: 1px solid black; border-collapse: collapse; } th button { background-color: transparent; border: none; cursor: pointer; font: inherit; color:inherit; width: 100%; } th button[data-dir="asc"]::after { content: " " url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 13' xml:space='preserve' width='13' height='13' transform='scale(1 -1)'%3E%3Cpath d='M2.039 5.171c.114.114.25.172.406.172h8.107a.55.55 0 0 0 .406-.172c.114-.114.172-.25.172-.406s-.057-.292-.172-.406L6.906.302C6.792.187 6.658.13 6.5.13s-.292.057-.406.172L2.039 4.355a.557.557 0 0 0-.172.406.541.541 0 0 0 .172.408zM6.5 12.473a.163.163 0 0 1-.127-.055L2.319 8.364a.159.159 0 0 1-.055-.127c0-.042.01-.081.055-.127s.084-.055.127-.055h8.107c.042 0 .081.01.127.055s.055.084.055.127a.163.163 0 0 1-.055.127l-4.052 4.054c-.047.045-.084.055-.127.055m0 .396a.55.55 0 0 0 .406-.172l4.054-4.054a.557.557 0 0 0 .172-.406.549.549 0 0 0-.172-.406.557.557 0 0 0-.406-.172H2.447a.549.549 0 0 0-.406.172.557.557 0 0 0-.172.406.55.55 0 0 0 .172.406l4.054 4.053c.114.114.25.172.406.172z' fill='%23000'/%3E%3C/svg%3E"); } th button[data-dir="desc"]::after { content: " " url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 13' xml:space='preserve' width='13' height='13'%3E%3Cpath d='M2.039 5.171c.114.114.25.172.406.172h8.107a.55.55 0 0 0 .406-.172c.114-.114.172-.25.172-.406s-.057-.292-.172-.406L6.906.302C6.792.187 6.658.13 6.5.13s-.292.057-.406.172L2.039 4.355a.557.557 0 0 0-.172.406.541.541 0 0 0 .172.408zM6.5 12.473a.163.163 0 0 1-.127-.055L2.319 8.364a.159.159 0 0 1-.055-.127c0-.042.01-.081.055-.127s.084-.055.127-.055h8.107c.042 0 .081.01.127.055s.055.084.055.127a.163.163 0 0 1-.055.127l-4.052 4.054c-.047.045-.084.055-.127.055m0 .396a.55.55 0 0 0 .406-.172l4.054-4.054a.557.557 0 0 0 .172-.406.549.549 0 0 0-.172-.406.557.557 0 0 0-.406-.172H2.447a.549.549 0 0 0-.406.172.557.557 0 0 0-.172.406.55.55 0 0 0 .172.406l4.054 4.053c.114.114.25.172.406.172z' fill='%23000'/%3E%3C/svg%3E"); }
HTML
<table width='100%'> <thead> <tr> <th width='20%'>Image</th> <th width='20%'><button data-dir=''>Number</button></th> <th width='40%'><button data-dir=''>Name</button></th> <th width='20%'><button data-dir=''>Postal code</button></th> </tr> </thead> <tbody> <tr> <td>IMG1</td> <td>xxx</td> <td>John Johnson</td> <td>56430</td> </tr> <tr> <td>IMG2</td> <td>yyy</td> <td>Sally Johnson</td> <td>56430</td> </tr> </tbody> </table>
内容的提问来源于stack exchange,提问作者AnonymousJ
相关产品推荐
相关产品推荐

