我想根据版本号对表格进行排序,最高的版本在顶部。如果单元格以“ v”开头,后跟一个数字,则被视为版本号。否则,应按字母顺序在表格底部排序。
当前的结果完全是我想要的结果,除了v2.0应该在v2a之前,而v2a应该在v2b之前。我知道我的parseFloat()
搞砸了,但是我怎样才能更好地做到这一点呢?
function sortTable(table, order, selector, target) {
selector = selector || 'th:first-child, td:first-child';
var asc = order === 'asc';
target = target || '';
var tbody = table.querySelector('tbody') || table;
var nodes = tbody.querySelectorAll('tr');
var sortedNodes = Array.prototype.slice.apply(nodes);
sortedNodes.sort(function (a, b) {
var textA = a.querySelector(selector).textContent;
var textB = b.querySelector(selector).textContent;
if( target == 'versions' )
{
if (textA.match(/^v\d.*/i)) {
textA = parseFloat(textA.substr(1));
}
if (textB.match(/^v\d.*/i)) {
textB = parseFloat(textB.substr(1));
}
}
result = textA - textB;
if (isNaN(result))
{
return (asc && textB.toString() != '' ) ? textA.toString().localeCompare(textB) : textB.toString().localeCompare(textA);
}
else
{
return (asc) ? -result : result;
}
});
tbody.textContent = '';
for (var i = 0; i < sortedNodes.length; i++) {
tbody.appendChild(sortedNodes[i]);
}
}
sortTable(document.getElementById('versions'), 'asc', '', 'versions');
<table id="versions">
<tbody>
<tr><td>Text</td></tr>
<tr><td>v2b</td></tr>
<tr><td>v3.0</td></tr>
<tr><td>v2a</td></tr>
<tr><td></td></tr>
<tr><td>v2.0</td></tr>
<tr><td>No version number</td></tr>
<tr><td>v1.0 Work in Progress</td></tr>
</tbody>
</table>
答案 0 :(得分:1)
您可以使用RegEx拆分版本号和后缀,以确保正确处理数字部分。
我不是100%肯定此代码段涵盖了所有可能的情况。它可以处理您的样本数据,并且可以很容易地进行调整以处理边缘情况(如果存在)。
为了简化和简化排序,我省略了DOM内容。我更新了代码段,以演示除原始文本值之外的基本表排序。
const values = [
"Text",
"v2b",
"v3.0",
"v2a",
"",
"v2.0",
"v30.4alpha",
"No version number",
"v1.0 Work in Progress",
];
// regex to separate the numeric version from the suffix
// e.g. "v2.0a" => ["2.0", "a"]
const version = /v(\d+(?:\.\d+)*)(.*)/;
function getSortValue (item) {
if (item == null ) {
return item;
}
// might want to do something more robust here.
// if it's not a string this assumes it's a tr
// and the first cell has the text we care about.
return typeof item === "string"
? item
: item.firstChild.textContent;
}
function sort(av, bv) {
const a = getSortValue(av);
const b = getSortValue(bv);
if (b && !a) {
return 1;
}
if (a && !b) {
return -1;
}
// get the numeric version and suffix for each item,
// OR'd with [] for cases where the regex doesn't match
const [, aVersion = 0, aSuffix = ''] = version.exec(a) || [];
const [, bVersion = 0, bSuffix = ''] = version.exec(b) || [];
// sort on the numeric portion
const versionDiff = parseFloat(bVersion) - parseFloat(aVersion);
// if the numeric versions are the same
// sort on the suffix
if (versionDiff === 0) {
return aSuffix.localeCompare(bSuffix) || a.localeCompare(b);
}
// numeric versions are different; sorting them is enough.
return versionDiff;
}
// sort raw text values
document.querySelector('pre').innerHTML = JSON.stringify(values.sort(sort), null, 2);
// sort table rows
const rows = Array.from(document.querySelectorAll('tr'));
rows.sort(sort);
const tbody = rows[0].parentElement;
rows.forEach(r => tbody.append(r));
table {
width: 100%;
font-family: monospace;
font-size: 14px;
}
td {
padding: 4px 8px;
}
tr:nth-child(2n - 1) {
background: #eee;
}
<table id="versions">
<tbody>
<tr><td>Text</td></tr>
<tr><td>v2b</td></tr>
<tr><td>v3.0</td></tr>
<tr><td>v2a</td></tr>
<tr><td></td></tr>
<tr><td>v2.0</td></tr>
<tr><td>No version number</td></tr>
<tr><td>v1.0 Work in Progress</td></tr>
</tbody>
</table>
<pre></pre>
答案 1 :(得分:0)
问题在于您的排序路由只考虑了第二个字符,因此2a和2b之间并没有真正的区别。
我建议从第二个字符(1、2和3)(下一个字符(a,b 、.)的ASCII码)中构造一个十进制数,并最终比较这些值。
function sortTable(table, order, selector, target) {
selector = selector || 'th:first-child, td:first-child';
var asc = order === 'asc';
target = target || '';
var tbody = table.querySelector('tbody') || table;
var nodes = tbody.querySelectorAll('tr');
var sortedNodes = Array.prototype.slice.apply(nodes);
sortedNodes.sort(function(a, b) {
var textA = a.querySelector(selector).textContent;
var textB = b.querySelector(selector).textContent;
var temp;
var temp2;
if (target == 'versions') {
if (textA.match(/^v\d.*/i)) {
temp2 = textA.charCodeAt(2);
if (temp2 == 46) {
temp2 = 0;
} else {
temp2 = (100 - textA.charCodeAt(2)) / 100
}
temp = (parseInt(textA.substr(1)) + temp2);
textA = temp;
}
if (textB.match(/^v\d.*/i)) {
temp2 = textB.charCodeAt(2);
if (temp2 == 46) {
temp2 = 0;
} else {
temp2 = (100 - textB.charCodeAt(2)) / 100
}
temp = (parseInt(textB.substr(1)) + temp2);
textB = temp;
}
}
result = textA - textB;
if (isNaN(result)) {
return (asc) ? textA.toString().localeCompare(textB) : textB.toString().localeCompare(textA);
} else {
return (asc) ? -result : result;
}
});
tbody.textContent = '';
for (var i = 0; i < sortedNodes.length; i++) {
tbody.appendChild(sortedNodes[i]);
}
}
sortTable(document.getElementById('versions'), 'asc', '', 'versions');
<table id="versions">
<tbody>
<tr>
<td>Text</td>
</tr>
<tr>
<td>v2b</td>
</tr>
<tr>
<td>v3.0</td>
</tr>
<tr>
<td>v2a</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>v2.0</td>
</tr>
<tr>
<td>No version number</td>
</tr>
<tr>
<td>v1.0 Work in Progress</td>
</tr>
</tbody>
</table>