我有一个JS脚本的问题,我正试图放在一起。我有一个HTML表格,它有300行左右的地方。我已经做了一个排序函数,可以使表头可点击并启动排序功能。我想集成一个进度条,因为在单击标题后,在较大的表(500 - 1000行)中,表需要一些时间来排序(IE是一个大罪犯)。进度条会告诉他们在排序完成之前还剩多少时间。我想到的方法是基于排序循环的进度调整div元素。问题是,我似乎无法弄清楚如何将这样的例程集成到我的循环中。Javascript:如何更新'for'循环中的进度条
我研究这个问题,并注意到这一点:How to change progress bar in loop? 和这样的:Using setTimeout to update progress bar when looping over multiple variables
第二个话题有几个演示该做的基本上是我想尽可能的进度条去做些什么。但是,任何时候我尝试实现这两个职位我要么所示的解决方案:
A - 崩溃的浏览器
乙 - 进度条显示工作,但是从0 - 100%瞬间,而不是渐进。
我希望有人能带领我在正确的方向上做什么。此表排序进度指示器必须使用本地JS来完成,因为内容必须可脱机使用,因此我不能通过CDN包含任何jQuery库,并且不希望整个jQuery库包含该文档。
我用我的代码创建了一个JS小提琴。我已经删除了我的进度条代码,因为我一直在崩溃浏览器,所以只要脚本去的就是排序相关的代码。 jsfiddle
这里是JS本身:
//Change this variable to match the "id" attribute of the
//table that is going to be operated on.
var tableID = "sortable";
/**
* Attach click events to all the <th> elements in a table to
* call the tableSort() function. This function assumes that cells
* in the first row in a table are <th> headers tags and that cells
* in the remaining rows are <td> data tags.
*
* @param table The table element to work with.
* @return void
*/
function initHeaders(table) {
//Get the table element
table = document.getElementById(table);
//Get the number of cells in the header row
var l = table.rows[0].cells.length;
//Loop through the header cells and attach the events
for(var i = 0; i < l; i++) {
if(table.rows[0].cells[i].addEventListener) { //For modern browsers
table.rows[0].cells[i].addEventListener("click", tableSort, false);
} else if(table.rows[0].cells[i].attachEvent) { //IE specific method
table.rows[0].cells[i].attachEvent("onclick", tableSort);
}
}
}
/**
* Compares values in a column of a table and then sorts the table rows.
* Subsequent calls to this function will toggle a row between ascending
* and descending sort directions.
*
* @param e The click event passed in from the browser.
* @return mixed No return value if operation completes successfully, FALSE on error.
*/
function tableSort(e) {
/**
* Checks to see if a value is numeric.
*
* @param n The incoming value to check.
* @return bool TRUE if value is numeric, FALSE otherwise.
*/
tableSort.isNumeric = function (n) {
var num = false;
if(!isNaN(n) && isFinite(n)) {
num = true;
}
return num;
}
//Get the element from the click event that was passed.
if(e.currentTarget) { //For modern browsers
e = e.currentTarget;
} else if(window.event.srcElement) { //IE specific method
e = window.event.srcElement;
} else {
console.log("Unable to determine source event. Terminating....");
return false;
}
//Get the index of the cell, will be needed later
var ndx = e.cellIndex;
//Toggle between "asc" and "desc" depending on element's id attribute
if(e.id == "asc") {
e.id = "desc";
} else {
e.id = "asc";
}
//Move up from the <th> that was clicked and find the parent table element.
var parent = e.parentElement;
var s = parent.tagName;
while(s.toLowerCase() != "table") {
parent = parent.parentElement;
s = parent.tagName;
}
/*
Executes two different loops. A "for" loop to control how many
times the table rows are passed looking for values to sort and a
"while" loop that does the actual comparing of values. The "for"
loop also controls how many times the embedded "while" loop will
run since each iteration with force at least one table row into
the correct position.
*/
//var interval = setInterval(function() { progress.updateProgress() } , 100);
var rows = parent.tBodies[0].rows.length; //Isolate and count rows only in the <tbody> element.
if(rows > 1) { //Make sure there are enough rows to bother with sorting
var v1; //Value 1 placeholder
var v2; //Value 2 placeholder
var tbody = parent.tBodies[0]; //Table body to manipulate
//Start the for loop (controls amount of table passes)
for(i = 0; i < rows; i++) {
var j = 0; //Counter for swapping routine
var offset = rows - i - 1; //Stops next loop from overchecking
// WANT TO UPDATE PROGRESS BAR HERE
//Start the while loop (controls number of comparisons to make)
while(j < offset) {
//Check to make sure values can be extracted before proceeding
if(typeof tbody.rows[j].cells[ndx].innerHTML !== undefined && typeof tbody.rows[j + 1].cells[ndx].innerHTML !== undefined) {
//Get cell values and compare
v1 = tbody.rows[j].cells[ndx].innerHTML;
v2 = tbody.rows[j + 1].cells[ndx].innerHTML;
if(tableSort.isNumeric(v1) && tableSort.isNumeric(v2)) {
//Dealing with two numbers
v1 = new Number(v1);
v2 = new Number(v2);
if(v1 > v2) {
if(e.id == "asc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
} else {
if(e.id == "desc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
}
} else if(tableSort.isNumeric(v1) && !tableSort.isNumeric(v2)) {
//v2 is a string, v1 is a number and automatically wins
if(e.id == "asc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
} else if(!tableSort.isNumeric(v1) && tableSort.isNumeric(v2)) {
//v1 is a string, v2 is a number and automatically wins
if(e.id == "desc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
} else {
//Both v1 and v2 are strings, use localeCompare()
if(v1.localeCompare(v2) > 0) {
if(e.id == "asc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
} else {
if(e.id == "desc") { //v1 moves down
tbody.insertBefore(tbody.rows[j + 1], tbody.rows[j]);
}
}
}
j++;
} else {
console.log("One of the values turned up undefined");
}
}
}
}
}
//Wait until DOM is ready and then initialize the table headers.
window.onload = function() {
initHeaders(tableID);
}
在此先感谢任何人谁可以点我在正确的方向。
----- 编辑: -----好了,所以在这里读书的答案,使一些大幅修改,我是如何处理事情我想出了一个更好的解决方案了。进度条并不是我想要的,但它很接近。 (虽然我认为它正在显示在页面上,就像排序准备完成时一样)。
我修改了我的循环以执行O(n log n)快速排序,而不是直接修改DOM我反而隔离表行来排序并将它们复制到一个数组中。然后我直接在数组上进行排序,一旦完成,我重建行,然后删除旧行并添加新行。排序时间显着减少。
看一看:http://jsfiddle.net/jnBmp/5/
这里是新的JS代码:
//Change this variable to match the "id" attribute of the
//table that is going to be operated on.
var tableID = "sortable";
/**
* Attach click events to all the <th> elements in a table to
* call the tableSort() function. This function assumes that cells
* in the first row in a table are <th> headers tags and that cells
* in the remaining rows are <td> data tags.
*
* @param table The table element to work with.
* @return void
*/
function initHeaders(table) {
//Get the table element
table = document.getElementById(table);
//Get the number of cells in the header row
var l = table.rows[0].cells.length;
//Loop through the header cells and attach the events
for(var i = 0; i < l; i++) {
if(table.rows[0].cells[i].addEventListener) { //For modern browsers
table.rows[0].cells[i].addEventListener("click", tableSort, false);
} else if(table.rows[0].cells[i].attachEvent) { //IE specific method
table.rows[0].cells[i].attachEvent("onclick", tableSort);
}
}
}
function tableSort(e) {
var runs = 0;
var pix = 0;
var ndx = 0;
var dir = "right";
var interval = false;
//Get the element from the click event that was passed.
if(e.currentTarget) { //For modern browsers
e = e.currentTarget;
} else if(window.event.srcElement) { //IE specific method
e = window.event.srcElement;
} else {
console.log("Unable to determine source event. Terminating....");
return false;
}
//Get the index of the cell, will be needed later
ndx = e.cellIndex;
//Toggle between "asc" and "desc" depending on element's id attribute
if(e.id == "asc") {
e.id = "desc";
} else {
e.id = "asc";
}
//Move up from the <th> that was clicked and find the parent table element.
var parent = e.parentElement;
var s = parent.tagName;
while(s.toLowerCase() != "table") {
parent = parent.parentElement;
s = parent.tagName;
}
//Get the rows to operate on as an array
var rows = document.getElementById("replace").rows;
var a = new Array();
for(i = 0; i < rows.length; i++) {
a.push(rows[i]);
}
//Show progress bar ticker
document.getElementById("progress").style.display = "block";
/**
* Show the progress bar ticker animation
*
* @param pix The current pixel count to set the <div> margin at.
*/
function updateTicker(pix) {
var tick = document.getElementById("progressTicker");
document.getElementById("progressText").style.display = "block";
document.getElementById("progressText").innerHTML = "Sorting table...please wait";
if(dir == "right") {
if(pix < 170) {
pix += 5;
tick.style.marginLeft = pix + "px";
} else {
dir = "left";
}
} else {
if(pix > 0) {
pix -= 5;
tick.style.marginLeft = pix + "px";
} else {
dir = "left";
}
}
interval = window.setTimeout(function() { updateTicker(pix); }, 25);
}
updateTicker(pix);
/**
* Checks to see if a value is numeric.
*
* @param n The incoming value to check.
* @return bool TRUE if value is numeric, FALSE otherwise.
*/
isNumeric = function (n) {
var num = false;
if(!isNaN(n) && isFinite(n)) {
num = true;
}
return num;
}
/**
* Compares two values and determines which one is "bigger".
*
* @param x A reference value to check against.
* @param y The value to be determined bigger or smaller than the reference.
* @return TRUE if y is greater or equal to x, FALSE otherwise
*/
function compare(x, y) {
var bigger = false;
x = x.cells[ndx].textContent;
y = y.cells[ndx].textContent;
//console.log(e.id);
if(isNumeric(x) && isNumeric(y)) {
if(y >= x) {
bigger = (e.id == "asc") ? true : false;
} else {
bigger = (e.id == "desc") ? true : false;
}
} else {
if(y.localeCompare(x) >= 0) {
bigger = (e.id == "asc") ? true : false;
} else {
bigger = (e.id == "desc") ? true : false;
}
}
return bigger;
}
/**
* Performs a quicksort O(n log n) on an array.
*
* @param array The array that needs sorting
* @return array The sorted array.
*/
function nlognSort(array) {
runs++
if(array.length > 1) {
var big = new Array();
var small = new Array();
var pivot = array.pop();
var l = array.length;
for(i = 0; i < l; i++) {
if(compare(pivot,array[i])) {
big.push(array[i]);
} else {
small.push(array[i]);
}
}
return Array.prototype.concat(nlognSort(small), pivot, nlognSort(big));
} else {
return array;
}
}
//Run sort routine
b = nlognSort(a);
//Rebuild <tbody> and replace new with the old
var tbody = document.createElement("tbody");
var l = b.length;
for(i = 0; i < l; i++) {
tbody.appendChild(b.shift());
}
parent.removeChild(document.getElementById("replace"));
parent.appendChild(tbody);
tbody.setAttribute("id","replace");
setTimeout(function() {
document.getElementById("progress").style.display = "none";
document.getElementById("progressText").style.display = "none";
clearTimeout(interval);
},1500);
}
window.onload = function() {
initHeaders(tableID);
}
再次感谢大家!
起初我试图通过使用本地['Array :: sort'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects /数组/排序)与'O(n log n)',你当前的算法有'O(n²)'。只有这样做没有帮助,你将不得不编写自己的快速和异步排序函数(从当前代码质量来看,这看起来有点过头了)。 – Bergi
不要在原地排序DOM。尽管JavaScript本身可以很快排序,但DOM访问速度可能会很慢,尤其是在较旧的浏览器上! –
这对于重新排列和更新进度条来说太慢了。你可能会尝试设置可见性:在排序时隐藏在桌面上,这可以避免重绘,并且在某些条件下大大加快了操作速度。 – dandavis