Следующий JavaScript работает в большинстве случаев (в алфавитном порядке), и он должен игнорировать новые строки или пробелы, а также должен игнорировать внутренний HTML. Однако при сортировке столбца 2 он не соответствует логической нумерации 1, 2, 14, 17 ..., поскольку сначала сортирует 1, затем 2 и т. д. Неверно в числовом виде.
Мне нужно, чтобы он одновременно следовал обоим правилам сортировки по алфавиту и по номерам. Я видел этот пост о проблеме, но не могу его реализовать.
window.onload = function() {
document.querySelectorAll('th').forEach((element) => { // Table headers
element.addEventListener('click', function() {
let table = this.closest('table');
// If the column is sortable
if (this.querySelector('span')) {
let order_icon = this.querySelector('span');
let order = encodeURI(order_icon.innerHTML).includes('%E2%86%91') ? 'desc' : 'asc';
let separator = '-----'; // Separate the value of it's index, so data keeps intact
let value_list = {}; // <tr> Object
let obj_key = []; // Values of selected column
let string_count = 0;
let number_count = 0;
// <tbody> rows
table.querySelectorAll('tbody tr').forEach((line, index_line) => {
// Value of each field
let key = line.children[element.cellIndex].textContent.toUpperCase().trim();
// Check if value is date, numeric or string
if (line.children[element.cellIndex].hasAttribute('data-timestamp')) {
// if value is date, we store it's timestamp, so we can sort like a number
key = line.children[element.cellIndex].getAttribute('data-timestamp');
} else if (key.replace('-', '').match(/^[0-9,.]*$/g)) {
number_count++;
} else {
string_count++;
}
value_list[key + separator + index_line] = line.outerHTML.replace(/(\t)|(\n)/g, ''); // Adding <tr> to object
obj_key.push(key + separator + index_line);
});
if (string_count === 0) { // If all values are numeric
obj_key.sort(function(a, b) {
return a.split(separator)[0] - b.split(separator)[0];
});
} else {
obj_key.sort();
}
if (order === 'desc') {
obj_key.reverse();
order_icon.innerHTML = '↓';
} else {
order_icon.innerHTML = '↑';
}
let html = '';
obj_key.forEach(function(chave) {
html += value_list[chave];
});
table.getElementsByTagName('tbody')[0].innerHTML = html;
}
});
});
}
<table border = "1" id = "myTable2" class = "resize-table-font">
<thead>
<tr>
<th>
<p align = "center">name <span>↑</span></p>
</th>
<th>
<p align = "center">ref <span>↑</span></p>
</th>
</tr>
</thead>
<tr>
<td>
1</td>
<td>
(book
3: 16)</td>
</tr>
<tr>
<td>
22</td>
<td>
(book 3: 16)</td>
</tr>
<tr>
<td>
book</td>
<td>
(book 2: 1-3)</td>
</tr>
<tr>
<td>
2</td>
<td>
(book 19: 12)</td>
</tr>
<tr>
<td>
how</td>
<td>
(book 19: 10, 12)</td>
</tr>
<tr>
<td>
when</td>
<td>
(book 19: 28; 21: 31)؟</td>
</tr>
<tr>
<td>
love</td>
<td>
(book 19: 30; 21: 31)؟</td>
</tr>
<tr>
<td>
3</td>
<td>
(book 10: 41; 14: 6, 7; 15: 3)</td>
</tr>
<tr>
<td>
tg</td>
<td>
(book 21: 30)</td>
</tr>
<tr>
<td>
web</td>
<td>
(book 19: 26; 21: 30)</td>
</tr>
<tr>
<td>
internet</td>
<td>
(book 15: 32; 19: 7)</td>
</tr>
<tr>
<td>
far4</td>
<td>
(book 19: 13)</td>
</tr>
<tr>
<td>
far3</td>
<td>
(book 21: 32)</td>
</tr>
<tr>
<td>
far33</td>
<td>
(book 20: 8; 21: 27)</td>
</tr>
</table>
Похоже, недопустимое вложение - это проблема, о которой упоминал Дэвид. Вы оборачиваете детей внутри tr в интервале. и код js зацикливается, чтобы определить сортировку, поэтому будет учитываться, что в tr есть только один дочерний элемент. Очистите свой код с помощью правильной вложенности.
Спасибо за ответ, я удалил все остальные теги и диапазоны (кроме тех, что в заголовке, которые необходимы для запуска js-скрипта, но все еще имеют ту же проблему с сортировкой. Или, если есть более простой js-код, он может быть используется для сортировки одного и того же контента.
Ниже приведен фрагмент кода, который сортирует вашу таблицу на основе текстового содержимого ячеек в столбце таблицы, который необходимо отсортировать.
Я попытался изменить ваш существующий код, но многое нужно было переопределить. Однако основная структура остается, и то, как вы пытались отсортировать таблицу, все еще на месте. Я использовал более описательные имена переменных, чтобы упростить отслеживание/отладку и интеграцию обратно в исходный код.
window.onload = function() {
// Table headers
document.querySelectorAll('th').forEach((elem) => {
elem.addEventListener('click', headerClick);
});
};
function headerClick(e) {
// 'this' keyword can be used. 'e.currentTarget' makes
// it easier to interpret what is the target element.
const headerCellEl = e.currentTarget;
// If the column is NOT sortable then exit this function
if (!headerCellEl.querySelector('.sortable')) {
return;
}
// Navigate up from the header cell element to get
// the '<table>' element.
let table = headerCellEl.closest('table');
// Navigate down from the 'table' element to get
// all of the row elements in the table's body.
let tableRows = table.querySelectorAll('tbody tr');
const cellIndex = headerCellEl.cellIndex;
let order_icon = headerCellEl.querySelector('.sortable');
let order = encodeURI(order_icon.innerHTML).includes('%E2%86%91') ? 'desc' : 'asc';
// Update the sort arrow
order_icon.innerHTML = order === 'desc' ? '↓' : '↑';
let cellList = [];
tableRows.forEach(rowEl => {
// Value of each field
let textContent = rowEl.children[cellIndex].textContent.toUpperCase().trim();
// stackoverflow.com/questions/31412765/regex-to-remove-white-spaces-blank-lines-and-final-line-break-in-javascript
const condensedHtml = condenseHTML(rowEl.outerHTML);
cellList.push({
textContent: textContent,
rowHtml: condensedHtml
});
});
const sortedCellList = sortCellList(cellList, order);
let html = '';
sortedCellList.forEach(entry => {
html += entry.rowHtml;
});
table.getElementsByTagName('tbody')[0].innerHTML = html;
}
// stackoverflow.com/questions/31412765/regex-to-remove-white-spaces-blank-lines-and-final-line-break-in-javascript
function condenseHTML(html) {
return html.split('\n')
.map(s => {
return s.replace(/^\s*|\s*$/g, "");
})
.filter(x => {
return x;
})
.join("");
}
// https://stackoverflow.com/questions/2802341/natural-sort-of-alphanumerical-strings-in-javascript
// "If you have an array of objects, you can do it like this: "
// Answer: https://stackoverflow.com/a/52728388
function sortCellList(cellList, order) {
if (order === 'desc') {
return cellList.sort(function(a, b) {
return a.textContent.localeCompare(b.textContent, undefined, {
numeric: true,
sensitivity: 'base'
});
});
}
return cellList.sort(function(a, b) {
return b.textContent.localeCompare(a.textContent, undefined, {
numeric: true,
sensitivity: 'base'
});
});
}
<table border = "1" id = "myTable2" class = "resize-table-font">
<thead>
<tr>
<th>
<p align = "center">name <span class = "sortable">↑</span></p>
</th>
<th>
<p align = "center">ref <span class = "sortable">↑</span></p>
</th>
</tr>
</thead>
<tr>
<td>
1
</td>
<td>
(book 3: 16)
</td>
</tr>
<tr>
<td>
22
</td>
<td>
(book 3: 16)
</td>
</tr>
<tr>
<td>
book
</td>
<td>
(book 2: 1-3)
</td>
</tr>
<tr>
<td>
2
</td>
<td>
(book 19: 12)
</td>
</tr>
<tr>
<td>
how
</td>
<td>
(book 19: 10, 12)
</td>
</tr>
<tr>
<td>
when
</td>
<td>
(book 19: 28; 21: 31)؟
</td>
</tr>
<tr>
<td>
love
</td>
<td>
(book 19: 30; 21: 31)؟
</td>
</tr>
<tr>
<td>
3
</td>
<td>
(book 10: 41; 14: 6, 7; 15: 3)
</td>
</tr>
<tr>
<td>
tg
</td>
<td>
(book 21: 30)
</td>
</tr>
<tr>
<td>
web
</td>
<td>
(book 19: 26; 21: 30)
</td>
</tr>
<tr>
<td>
internet
</td>
<td>
(book 15: 32; 19: 7)
</td>
</tr>
<tr>
<td>
far4
</td>
<td>
(book 19: 13)
</td>
</tr>
<tr>
<td>
far3
</td>
<td>
(book 21: 32)
</td>
</tr>
<tr>
<td>
far33
</td>
<td>
(book 20: 8; 21: 27)
</td>
</tr>
</table>
Локально что-то обнаружил, что иногда при сортировке убирает пробелы помимо вкладок вложенности. Где в коде можно исправить эту проблему? (Я отредактировал исходную таблицу, добавив «ввод» после пробела в строке 16 — после book
).
Я использовал функцию, которая сжимает HTML. Имя функции condenseHTML
. Замените вызов этой функции в строке: const condensedHtml = condenseHTML(rowEl.outerHTML);
и замените его исходным кодом, извлекающим внешний HTML-код строки: const condensedHtml = rowEl.outerHTML.replace(/(\t)|(\n)/g, '');
. Однако метод replace
заменяет вкладки (\t
) пустой строкой. Удалите использование \t
, если вы планируете вести вкладки.
Ваша вложенность недействительна (единственный допустимый дочерний элемент
<tr>
— это<th>
или<td>
(у вас есть хотя бы один<span>
, обертывающий<th>
); элемент<font>
устарел с HTML 4.1,align
,cellpadding
иcellspacing
Атрибуты должны управляться с помощью CSS (text-align
,padding
иborder-spacing
соответственно). Я еще не просматривал JavaScript, но настоятельно рекомендую вам привести в порядок и исправить свой HTML.