如何使用d3.js实现表格按不同列动态切换排序功能
问题修复方案
问题根因
- 无法切换排序的核心原因:你获取排序字段时直接取了整个class属性值,表头元素的class是
box hrbox name这类多类值,和你判断的"name"完全不匹配,导致排序逻辑判断异常;其次你不需要每次重绘表格时重复绑定表头点击事件,表头是静态元素,仅需初始化绑定一次即可。 - 排序逻辑无法简化的原因:你用了
.运算符访问属性,这种写法会把sortWhich当做固定属性名而非变量,换成方括号[]即可实现动态属性访问。
修复后代码
修改后的JS部分
const originalData = [ { "name": "Dave", "dept": "Marketing", "region": "South", "items": 28 }, { "name": "Amy", "dept": "IT", "region": "West", "items": 46 }, { "name": "John", "dept": "Sales", "region": "North", "items": 35 }, { "name": "Sarah", "dept": "Communications", "region": "North", "items": 13 } ] drawTable(originalData) sortTable() // 仅初始化绑定一次表头事件,不需要传数据 function drawTable(data) { d3.select('#data-table').remove() let table = d3.select('#table').append('div').attr('id', 'data-table') let row = table.selectAll('.row') .data(data) .enter() .append('div') .attr('class', 'row') let grid = row .append('div') .attr('class', 'grid') grid.append('div').attr('class', 'box').html(d => d.name) grid.append('div').attr('class', 'box').html(d => d.dept) grid.append('div').attr('class', 'box').html(d => d.region) grid.append('div').attr('class', 'box').html(d => d.items) } function sortTable() { d3.selectAll(".hrbox").on('click', function () { // 提取当前点击的列名,直接取元素内的文本 const sortField = d3.select(this).text().trim() // 先拷贝原始数组,避免原地排序修改原始数据 const sortedData = [...originalData].sort((a, b) => d3.ascending(a[sortField], b[sortField])) drawTable(sortedData) }) }
可选优化(更稳定的字段获取)
如果怕表头文本和属性名不一致,可以给每个表头加data-field属性,HTML部分修改表头如下:
<div class="box hrbox" data-field="name"> <div>name</div> </div> <div class="box hrbox" data-field="dept"> <div>dept</div> </div> <div class="box hrbox" data-field="region"> <div>region</div> </div> <div class="box hrbox" data-field="items"> <div>items</div> </div>
对应的JS中获取排序字段的代码改成:
const sortField = d3.select(this).attr('data-field')
该方案完全不需要if判断,新增列只要给表头加对应data-field属性即可自动支持排序,也兼容表头显示文本和属性名不一致的场景。
功能验证
修改后点击任意表头即可直接切换对应列排序,无需刷新页面,排序逻辑仅需1行即可完成,不需要多组条件判断。
内容的提问来源于stack exchange,提问作者sprucegoose
相关产品推荐
相关产品推荐

