JS table 排序在 Chrome 上失败
JS table sorting fail on Chrome
我正在开发一个允许人们参加 erg 赛艇在线比赛的网站。
我显示了一个很大的 table(600 多行),其中包含排名、名称和其他字段,我想让访问者动态地对其进行排序(客户端 JS)。
我设置了一个在 Firefox 上运行良好的功能,但在 Chrome 浏览器上根本不起作用。
我真的看不出我的代码的哪一部分会带来这个问题,这就是我向您寻求帮助的原因!
我的 html 代码如下:
<table>
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>...</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
<td>...</td>
</tr>
</tbody>
</table>
还有我的JavaScript:
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length-1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', { sensitivity: 'base', numeric: true });
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
感谢您的帮助!
a.getElementsByTagName('td')
是一个相当昂贵的操作,在每次比较期间调用它会很慢。
Table 行有一个 cells
属性 包含所有 td
和 th
元素,您可以改用它。
let x = a.cells[n].innerText.toLowerCase();
let y = b.cells[n].innerText.toLowerCase();
您传递给 .sort()
的比较函数是 return 布尔值:
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
但是,.sort()
method 期望此比较函数为 return 一个数字。我怀疑 Firefox 正在为你宽容或做一些类型转换,而 Chrome 不是。如果我将其更改为:
return ((dir == 'asc' && 0 + compare) || (dir == 'desc' && 0 - compare));
...它将按预期排序。
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length - 1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', {
sensitivity: 'base',
numeric: true
});
return ((dir == 'asc' && 0 + compare) || (dir == 'desc' && 0 - compare));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
<table id="mytable">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
</tr>
<tr>
<td>3</td>
<td>USER 3</td>
</tr>
<tr>
<td>2</td>
<td>USER 2</td>
</tr>
<tr>
<td>4</td>
<td>USER 4</td>
</tr>
<tr>
<td>5</td>
<td>USER 5</td>
</tr>
<tr>
<td>6</td>
<td>USER 6</td>
</tr>
<tr>
<td>7</td>
<td>USER 7</td>
</tr>
<tr>
<td>8</td>
<td>USER 8</td>
</tr>
<tr>
<td>9</td>
<td>USER 9</td>
</tr>
<tr>
<td>10</td>
<td>USER 10</td>
</tr>
<tr>
<td>11</td>
<td>USER 11</td>
</tr>
<tr>
<td>12</td>
<td>USER 12</td>
</tr>
<tr>
<td>13</td>
<td>USER 13</td>
</tr>
<tr>
<td>14</td>
<td>USER 14</td>
</tr>
<tr>
<td>15</td>
<td>USER 15</td>
</tr>
<tr>
<td>16</td>
<td>USER 16</td>
</tr>
<tr>
<td>17</td>
<td>USER 17</td>
</tr>
<tr>
<td>18</td>
<td>USER 18</td>
</tr>
<tr>
<td>19</td>
<td>USER 19</td>
</tr>
<tr>
<td>20</td>
<td>USER 20</td>
</tr>
<tr>
<td>21</td>
<td>USER 21</td>
</tr>
<tr>
<td>22</td>
<td>USER 22</td>
</tr>
<tr>
<td>23</td>
<td>USER 23</td>
</tr>
<tr>
<td>24</td>
<td>USER 24</td>
</tr>
<tr>
<td>25</td>
<td>USER 25</td>
</tr>
<tr>
<td>26</td>
<td>USER 26</td>
</tr>
<tr>
<td>27</td>
<td>USER 27</td>
</tr>
<tr>
<td>28</td>
<td>USER 28</td>
</tr>
<tr>
<td>29</td>
<td>USER 29</td>
</tr>
<tr>
<td>30</td>
<td>USER 30</td>
</tr>
</tbody>
</table>
(供参考,这里是原始版本,其中只是一个布尔值 returned,排序根本不起作用):
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length - 1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', {
sensitivity: 'base',
numeric: true
});
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
<table id="mytable">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
</tr>
<tr>
<td>3</td>
<td>USER 3</td>
</tr>
<tr>
<td>2</td>
<td>USER 2</td>
</tr>
<tr>
<td>4</td>
<td>USER 4</td>
</tr>
<tr>
<td>5</td>
<td>USER 5</td>
</tr>
<tr>
<td>6</td>
<td>USER 6</td>
</tr>
<tr>
<td>7</td>
<td>USER 7</td>
</tr>
<tr>
<td>8</td>
<td>USER 8</td>
</tr>
<tr>
<td>9</td>
<td>USER 9</td>
</tr>
<tr>
<td>10</td>
<td>USER 10</td>
</tr>
<tr>
<td>11</td>
<td>USER 11</td>
</tr>
<tr>
<td>12</td>
<td>USER 12</td>
</tr>
<tr>
<td>13</td>
<td>USER 13</td>
</tr>
<tr>
<td>14</td>
<td>USER 14</td>
</tr>
<tr>
<td>15</td>
<td>USER 15</td>
</tr>
<tr>
<td>16</td>
<td>USER 16</td>
</tr>
<tr>
<td>17</td>
<td>USER 17</td>
</tr>
<tr>
<td>18</td>
<td>USER 18</td>
</tr>
<tr>
<td>19</td>
<td>USER 19</td>
</tr>
<tr>
<td>20</td>
<td>USER 20</td>
</tr>
<tr>
<td>21</td>
<td>USER 21</td>
</tr>
<tr>
<td>22</td>
<td>USER 22</td>
</tr>
<tr>
<td>23</td>
<td>USER 23</td>
</tr>
<tr>
<td>24</td>
<td>USER 24</td>
</tr>
<tr>
<td>25</td>
<td>USER 25</td>
</tr>
<tr>
<td>26</td>
<td>USER 26</td>
</tr>
<tr>
<td>27</td>
<td>USER 27</td>
</tr>
<tr>
<td>28</td>
<td>USER 28</td>
</tr>
<tr>
<td>29</td>
<td>USER 29</td>
</tr>
<tr>
<td>30</td>
<td>USER 30</td>
</tr>
</tbody>
</table>
我正在开发一个允许人们参加 erg 赛艇在线比赛的网站。
我显示了一个很大的 table(600 多行),其中包含排名、名称和其他字段,我想让访问者动态地对其进行排序(客户端 JS)。
我设置了一个在 Firefox 上运行良好的功能,但在 Chrome 浏览器上根本不起作用。
我真的看不出我的代码的哪一部分会带来这个问题,这就是我向您寻求帮助的原因!
我的 html 代码如下:
<table>
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
<th>...</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
<td>...</td>
</tr>
</tbody>
</table>
还有我的JavaScript:
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length-1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', { sensitivity: 'base', numeric: true });
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
感谢您的帮助!
a.getElementsByTagName('td')
是一个相当昂贵的操作,在每次比较期间调用它会很慢。
Table 行有一个 cells
属性 包含所有 td
和 th
元素,您可以改用它。
let x = a.cells[n].innerText.toLowerCase();
let y = b.cells[n].innerText.toLowerCase();
您传递给 .sort()
的比较函数是 return 布尔值:
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
但是,.sort()
method 期望此比较函数为 return 一个数字。我怀疑 Firefox 正在为你宽容或做一些类型转换,而 Chrome 不是。如果我将其更改为:
return ((dir == 'asc' && 0 + compare) || (dir == 'desc' && 0 - compare));
...它将按预期排序。
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length - 1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', {
sensitivity: 'base',
numeric: true
});
return ((dir == 'asc' && 0 + compare) || (dir == 'desc' && 0 - compare));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
<table id="mytable">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
</tr>
<tr>
<td>3</td>
<td>USER 3</td>
</tr>
<tr>
<td>2</td>
<td>USER 2</td>
</tr>
<tr>
<td>4</td>
<td>USER 4</td>
</tr>
<tr>
<td>5</td>
<td>USER 5</td>
</tr>
<tr>
<td>6</td>
<td>USER 6</td>
</tr>
<tr>
<td>7</td>
<td>USER 7</td>
</tr>
<tr>
<td>8</td>
<td>USER 8</td>
</tr>
<tr>
<td>9</td>
<td>USER 9</td>
</tr>
<tr>
<td>10</td>
<td>USER 10</td>
</tr>
<tr>
<td>11</td>
<td>USER 11</td>
</tr>
<tr>
<td>12</td>
<td>USER 12</td>
</tr>
<tr>
<td>13</td>
<td>USER 13</td>
</tr>
<tr>
<td>14</td>
<td>USER 14</td>
</tr>
<tr>
<td>15</td>
<td>USER 15</td>
</tr>
<tr>
<td>16</td>
<td>USER 16</td>
</tr>
<tr>
<td>17</td>
<td>USER 17</td>
</tr>
<tr>
<td>18</td>
<td>USER 18</td>
</tr>
<tr>
<td>19</td>
<td>USER 19</td>
</tr>
<tr>
<td>20</td>
<td>USER 20</td>
</tr>
<tr>
<td>21</td>
<td>USER 21</td>
</tr>
<tr>
<td>22</td>
<td>USER 22</td>
</tr>
<tr>
<td>23</td>
<td>USER 23</td>
</tr>
<tr>
<td>24</td>
<td>USER 24</td>
</tr>
<tr>
<td>25</td>
<td>USER 25</td>
</tr>
<tr>
<td>26</td>
<td>USER 26</td>
</tr>
<tr>
<td>27</td>
<td>USER 27</td>
</tr>
<tr>
<td>28</td>
<td>USER 28</td>
</tr>
<tr>
<td>29</td>
<td>USER 29</td>
</tr>
<tr>
<td>30</td>
<td>USER 30</td>
</tr>
</tbody>
</table>
(供参考,这里是原始版本,其中只是一个布尔值 returned,排序根本不起作用):
for (const table of document.getElementsByTagName('table')) {
const headers = table.querySelectorAll('thead tr th');
for (let i = 0; i < headers.length - 1; i++) {
headers[i].addEventListener('click', sortTable(i, table.id));
}
}
function sortTable(n, tableId) {
return () => {
const table = document.getElementById(tableId);
const newTable = document.createElement('table');
newTable.className = table.className;
newTable.id = table.id;
const tbody = document.createElement('tbody');
const thead = document.createElement('thead');
const rows = Array.from(table.rows);
thead.appendChild(rows.shift());
const th = thead.getElementsByTagName('th');
const dir = th[n].className == 'asc' ? 'desc' : 'asc';
rows.sort((a, b) => {
let x = a.getElementsByTagName('td')[n].innerText.toLowerCase();
let y = b.getElementsByTagName('td')[n].innerText.toLowerCase();
const compare = x.localeCompare(y, 'fr', {
sensitivity: 'base',
numeric: true
});
return ((dir == 'asc' && compare > 0) || (dir == 'desc' && compare < 0));
})
.forEach(row => tbody.appendChild(row));
for (const header of th) {
header.className = '';
}
th[n].className = dir;
newTable.appendChild(thead);
newTable.appendChild(tbody);
table.parentNode.replaceChild(newTable, table);
};
}
<table id="mytable">
<thead>
<tr>
<th>Rank</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>USER 1</td>
</tr>
<tr>
<td>3</td>
<td>USER 3</td>
</tr>
<tr>
<td>2</td>
<td>USER 2</td>
</tr>
<tr>
<td>4</td>
<td>USER 4</td>
</tr>
<tr>
<td>5</td>
<td>USER 5</td>
</tr>
<tr>
<td>6</td>
<td>USER 6</td>
</tr>
<tr>
<td>7</td>
<td>USER 7</td>
</tr>
<tr>
<td>8</td>
<td>USER 8</td>
</tr>
<tr>
<td>9</td>
<td>USER 9</td>
</tr>
<tr>
<td>10</td>
<td>USER 10</td>
</tr>
<tr>
<td>11</td>
<td>USER 11</td>
</tr>
<tr>
<td>12</td>
<td>USER 12</td>
</tr>
<tr>
<td>13</td>
<td>USER 13</td>
</tr>
<tr>
<td>14</td>
<td>USER 14</td>
</tr>
<tr>
<td>15</td>
<td>USER 15</td>
</tr>
<tr>
<td>16</td>
<td>USER 16</td>
</tr>
<tr>
<td>17</td>
<td>USER 17</td>
</tr>
<tr>
<td>18</td>
<td>USER 18</td>
</tr>
<tr>
<td>19</td>
<td>USER 19</td>
</tr>
<tr>
<td>20</td>
<td>USER 20</td>
</tr>
<tr>
<td>21</td>
<td>USER 21</td>
</tr>
<tr>
<td>22</td>
<td>USER 22</td>
</tr>
<tr>
<td>23</td>
<td>USER 23</td>
</tr>
<tr>
<td>24</td>
<td>USER 24</td>
</tr>
<tr>
<td>25</td>
<td>USER 25</td>
</tr>
<tr>
<td>26</td>
<td>USER 26</td>
</tr>
<tr>
<td>27</td>
<td>USER 27</td>
</tr>
<tr>
<td>28</td>
<td>USER 28</td>
</tr>
<tr>
<td>29</td>
<td>USER 29</td>
</tr>
<tr>
<td>30</td>
<td>USER 30</td>
</tr>
</tbody>
</table>