根据版本号对表进行排序

时间:2019-05-22 22:26:48

标签: javascript html

我想根据版本号对表格进行排序,最高的版本在顶部。如果单元格以“ 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>

2 个答案:

答案 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>