JSON数据填充HTML Select框排序异常,如何实现自然排序?
问题:Select框填充JSON数据时排序不符合预期
我用JSON数据填充HTML select框,功能正常但排序结果不对。当前显示顺序是 Line 1, Line 11, Line 13, Line 2,期望得到的顺序是 Line 1, Line 2, Line 11, Line 13。相关代码如下:
原JavaScript代码
var objs = [ { lineName: 'LINE 1', lineID: 'LI01' }, { lineName: 'LINE 2', lineID: 'LI02' }, { lineName: 'LINE 11', lineID: 'LI04' }, { lineName: 'LINE 13', lineID: 'LI05' } ]; const sorter2 = (sortBy) => (a, b) => a[sortBy].toLowerCase() > b[sortBy].toLowerCase() ? 1 : -1; objs.sort(sorter2('lineName')); console.log("Using sorter2 - passed param sortBy='lineName'", objs); for(var i=0; i<objs.length; i++) { var lineID = objs[i].lineID; var lineName = objs[i].lineName; $("#line").append("<option value='" + lineID + "'>" + lineName + "</option>"); }
原HTML代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <select id="line"> <option value="">Choose</option> </select>
解决方案
问题根源
当前排序逻辑是字符串字典序比较,字典序中"11"的字符顺序比"2"靠前(因为'1'的ASCII码小于'2'),所以会出现Line 11排在Line 2前面的情况。需要改用自然排序,基于名称中的数字数值进行比较。
修改后的排序函数
替换原有的sorter2函数,提取lineName中的数字转为整数后比较:
const sorterNatural = (sortBy) => (a, b) => { // 提取字符串中的数字部分并转为整数 const numA = parseInt(a[sortBy].match(/\d+/)[0], 10); const numB = parseInt(b[sortBy].match(/\d+/)[0], 10); // 通过数值差值实现升序排序 return numA - numB; };
完整修改后代码
var objs = [ { lineName: 'LINE 1', lineID: 'LI01' }, { lineName: 'LINE 2', lineID: 'LI02' }, { lineName: 'LINE 11', lineID: 'LI04' }, { lineName: 'LINE 13', lineID: 'LI05' } ]; const sorterNatural = (sortBy) => (a, b) => { const numA = parseInt(a[sortBy].match(/\d+/)[0], 10); const numB = parseInt(b[sortBy].match(/\d+/)[0], 10); return numA - numB; }; objs.sort(sorterNatural('lineName')); console.log("Using natural sort - passed param sortBy='lineName'", objs); for(var i=0; i<objs.length; i++) { var lineID = objs[i].lineID; var lineName = objs[i].lineName; $("#line").append("<option value='" + lineID + "'>" + lineName + "</option>"); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <select id="line"> <option value="">Choose</option> </select>
通用扩展方案
如果lineName格式可能变化(比如多组数字、前缀不同),可以用浏览器原生API实现更通用的自然排序:
const sorterGeneral = (sortBy) => (a, b) => { return a[sortBy].localeCompare(b[sortBy], undefined, { numeric: true, sensitivity: 'base' // 忽略大小写和重音差异 }); };
这个方法无需手动提取数字,兼容性覆盖绝大多数现代浏览器。
内容的提问来源于stack exchange,提问作者HiDayurie Dave
相关产品推荐
相关产品推荐

