まとめようとしている JS スクリプトに問題があります。300 行近くの HTML テーブルがあります。テーブル ヘッダーをクリック可能にして並べ替え機能を起動する並べ替え機能を作成しました。ヘッダーがクリックされた後の大きなテーブル (500 ~ 1000 行) では、テーブルの並べ替えに少し時間がかかるため、進行状況バーを統合したいと思います (IE は大きな違反者です)。プログレス バーは、並べ替えが完了するまでの残り時間を示します。私が考えていた方法は、並べ替えループの進行に基づいてサイズを変更する div 要素でした。問題は、そのようなルーチンをループに統合する方法を理解できないように見えることです。
私はこの問題を調査し、これに注意しました: How to change progress bar in loop? そしてこれ:複数の変数をループするときに setTimeout を使用して進行状況バーを更新する
2 番目のトピックには、プログレス バーに関する限り、基本的に私がやりたいことを行うデモがいくつかあります。ただし、これらの 2 つの投稿に示されているソリューションを実装しようとするときはいつでも、次のいずれかを行います。
A - ブラウザをクラッシュさせる
B - プログレス バーは機能しているように見えますが、漸進的ではなく、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);
}
みんなありがとう!