JavaScript Table sorting 2.0 (updated)

Source: Internet
Author: User

I am still so busy recently. Please update the program on May 1.
This version mainly adds and improves the following:
1. Use localeCompare to compare strings;
2. Multiple sorting objects can be used in a single sorting (used for sorting when values are equal );
3. Fixed some detected problems;
4. Improve the program structure. I personally think it is more flexible and convenient;
5. added the bool type comparison;
6. Add the attribute/property content;
7. Fixed the radio/checkbox status restoration bug in ie6/7;
8. added the custom value function.
<! DOCTYPE html PUBLIC "-// W3C // dtd xhtml 1.0 Transitional // EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ptml xmlns = "http://www.w3.org/1999/xhtml"> <pead> <meta http-equiv =" content-Type "content =" text/html; charset = gb2312 "/> <title> Table sorting </title> <style type =" text/css ">. odTable {width: 500px; border: 1px solid # ebeb; line-height: 20px; font-size: 12px; background: # FFF ;}. odTable thead td {background-color: # ebebeb ;}. odTable a {outline: none;/* ff */hide-focus: expression (this. hideFocus = true);/* ie */}. odTable a: link ,. odTable a: visited ,. odTable a: hover ,. odTable a: active {text-decoration: none; color: #333; padding-right: 15px ;}. odTable. up ,. odTable. down {background: url ([img]/upload/20090507150209227.jpg[/img]) right center no-repeat ;}. odTable. down {background-image: url ([img]/upload/20090507150209265.jpg[/img]);} </style> </pead> <body> <table border = "0" cellspacing = "0" cellpadding = "5" class = "odTable" id = "idTable"> <thead> <tr> <td align = "center"> ID </td> <td> name/type </td> <td width = "100" align = "center"> upload time </td> <td width = "50" align = "center"> size </td> <td width = "30" align = "center"> C </td> <td width = "30" align = "center"> R </td> </tr> </thead> <tbody> <tr> <td align =" center "> 1 </td> <td _ ext =" htm "> new.htm </td> <td align =" center "> 2008/9/12 </td> <td align =" right "_ order =" 9 "> 423.09 K </td> <td align =" center "> <input type =" checkbox "/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <td align = "center"> 2 </ td> <td _ ext = "js"> Scroller. js </td> <td align = "center"> 2008/9/23 </td> <td align = "right" _ order = "80"> 2.5 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio "/> </td> </tr> <td align = "center"> 3 </td> <td _ ext = "js"> AlertBox. js </td> <td align = "center"> 2008/9/23 </td> <td align = "right" _ order = "290"> 3.48 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio "/> </td> </tr> <td align = "center"> 4 </td> <td _ ext = "xml"> 1.xml</td> <td align = "center"> 2008/10/4 </td> <td align = "right" _ order = "19"> 11.13 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </ tr> <td align = "center"> 5 </td> <td _ ext = "xml"> 4.xml</td> <td align = "center"> 2008/10/4 </td> <td align = "right" _ order = "1000"> 351 B </td> <td align = "center"> <input type = "checkbox "/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <td align = "center"> 6 </td> <td _ ext = "htm"> news.htm </td> <td align = "center"> 2008/10/4 </td> <td align = "right" _ order = "14074"> 13.74 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <td align = "center"> 7 </td> <td _ ext = "js"> function. js </td> <td align = "center"> 2008/10/4 </td> <td align = "right" _ order = "2844"> 2.78 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio "/> </td> </tr> <td align = "center"> 8 </td> <td _ ext = "mp3"> secret garden-nocturne.pdf </td> <td align = "center"> 2008/9/20 </td> <td align = "right" _ order = "3111293"> 2.97 M </td> <td align = "center "> <input type =" checkbox "/> </td> <td align =" center "> <input name =" c "type =" radio "/> </td> </tr> <td align = "center"> 9 </td> <td _ ext = "doc"> elaborate on the specific procedure (1. doc </td> <td align =" center "> 2009/2/2 </td> <td align =" right "_ order =" 63488 "> 62 K </td> <td align =" center "> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <tr> <td align = "center"> 10 </td> <td _ ext = "doc"> detailed practices (2).doc </td> <td align = "center"> 2009/2/2 </ td> <td align = "right" _ order = "164352"> 160.5 K </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <td align = "center"> 11 </td> <td _ ext = "txt"> banned file preview function .txt </td> <td align = "center"> 2008/8/7 </td> <td align = "right" _ order = "860"> 860 B </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> <td align = "center"> 12 </td> <td _ ext = "txt"> excellent effect set .txt </td> <td align = "center"> 2009/2/2 </td> <td align = "right" _ order = "351"> 351 B </td> <td align = "center"> <input type = "checkbox"/> </td> <td align = "center"> <input name = "c" type = "radio"/> </td> </tr> </tbody> </table> has a Chinese prefix, sort by time in reverse order and ID in reverse order: <input name = "" type = "button" value = "Sort" id = "idBtn"/> </body> </ptml>
[Ctrl + A select all Note: If you need to introduce external Js, You need to refresh it to execute]
Packaging code
Procedure

1. Place the rows to be sorted into the tbody (the program will directly retrieve the rows of the tbody );

2. Place the sorting rows in an array;

This. Rows = Map (this. tBody. rows, function (o) {return o ;});

3. sort the array as needed (using the sort method of the array );

This. Rows. sort (Bind (this, this. Compare, orders, 0 ));

4. Use a document fragment (document. createDocumentFragment () to save the sorted rows;


Var oFragment = document. createDocumentFragment ();
ForEach (this. Rows, function (o) {oFragment. appendChild (o );});

Ps: Document fragments are not required, but we recommend that you use them more efficiently when using a large number of dom operations.

5. Insert the file fragments into the tbody.

This. tBody. appendChild (oFragment );


Program description

[Sorting function]

Sorting has to say the sort method in the Array. This is introduced in the manual: returns an Array object whose elements have been sorted. This method is used to sort an array.

By default, the sorting is performed in ascending order of ASCII characters. If you use parameters, you can customize the sorting method. The Compare program of the program uses the custom sorting method.
In general, the sorting function has two default parameters: Two Comparison objects. The program calls Compare with two Bind parameters as needed, so there are four parameters.
Note that the sorting function must return one of the following values:
Negative value if the first parameter is smaller than the second parameter.
Zero. If the two parameters are equal.
If the first parameter is greater than the second parameter.

After obtaining the comparison value (described later), compare the value.
If it is a string in the program, localeCompare is used to obtain the comparison result. Otherwise, the comparison result is directly subtracted:

Result = order. Compare? Order. Compare (value1, value2): // use custom sorting
Typeof value2 = "string "? Value1.localeCompare (value2): (value1-value2 );

If the Desc attribute is true (descending order), multiply by-1 on the result to get the opposite order: (order. Down? -1: 1) * result


[Obtain the comparison value]

The program obtains the comparison value from each tr Based on the sorting object and the GetValue method.
First, you can obtain the corresponding value through Index (td Index) and Attri (attribute.
If there is no suitable property to be compared, you can set a custom property for td to put this value (such as _ ext In the example ).
For custom attributes set in html, ie can use [x] and getAttribute, while ff can only be obtained using getAttribute (details will be provided later ).
Therefore, you only need to consider ff. The program uses in to determine whether this attribute can be obtained using [x:

Var td = tr. getElementsByTagName ("td") [order. Index]
, At = order. Attri, data = at in td? Td [at]: td. getAttribute ();

If the in operation is true, you can use a keyword to obtain the value. Otherwise, use getAttribute.
After the value is obtained, the comparison value is converted. Here, the Date is converted to an integer in the form of Date. parse for convenient comparison:

Switch (order. DataType. toLowerCase ()){
Case "int ":
Return parseInt (data) | 0;
Case "float ":
Return parseFloat (data) | 0;
Case "date ":
Return Date. parse (data) | 0;
Case "string ":
Default:
Return data. toString () | "";
}

Note that the Date. parse parameter must comply with the js Date Format (refer to here ).
Ps: If you think that adding a custom property does not conform to the standard, you can consider placing it in attributes such as title.


[Attribute/property]

When obtaining the comparison value, the in method is used to determine whether the [x] method can be used to determine whether the attribute belongs to attribute or property.
So what is the difference between attribute and property? This may not be noticed by many people. It may be the same thing.
To clarify that attribute and property are different, we need to first know what they are, which is hard to tell clearly. We can give some examples to understand them.
Here we first use ff as the standard, and then talk about the difference between ie. Take div as an example. Check the complete manual for creating a webpage and you will find that it has the following attributes:
ALIGN align
CLASS className
ID
TITLE title
......
The first column is attribute, and the second column is property.
Attribute is the property of dom elements in the document as html tags. property is the property of dom elements in js as objects.
For example, the class attribute should be used directly for dom as page elements in html, and the className attribute must be used for dom objects in js.
Attribute is case-insensitive, which makes most of the attribute and property look the same. This makes people mistakenly think of the same thing (of course, ie has a great responsibility ).
If you do not believe it, you can use ff to look at the following example:

<Div id = "t" tt = "1"> test </div>
<Script>
Var o = document. getElementById ('T ');
O ["tt"] = "2 ";
Document. writeln (o. getAttribute ("tt "));
Document. writeln (o ["tt"]);
</Script>

The getAttribute and [x] methods have different answers.
Here, we must first talk about the difference between the getAttribute and [x] methods. getAttribute and setAttribute are used to obtain and set the attribute,
The [x] method is used to obtain and set the property. This property is the same as the property of the js object we operate on in general.
Some people may have doubts. Do not all the id and title point to the same attribute? Will the attribute corresponding to the property be modified as well.
In fact, we can also customize an attribute like this, and test the following code in ff:

<Div id = "t" tt = "1"> test </div>
<Script>
Var o = document. getElementById ('T ');
O. _ defineSetter _ ("tt", function (x) {this. setAttribute ("tt", x );});
O. _ defineGetter _ ("tt", function () {return this. getAttribute ("tt ");});
O. tt = "2 ";
Document. writeln (o. getAttribute ("tt "));
Document. writeln (o ["tt"]);
</Script>

In this way, the attribute corresponding to "Modifying property will also be modified" is implemented.
From the test example, we can see that attribute and corresponding property can use different attribute names, such as the effect of class and className.
The attribute value can also be processed in Getter and then returned, just as the property value of href is in the complete path form of attribute.
The property can have no corresponding attribute. In turn, there is no corresponding attribute for a property like innerHTML.
Ps: The above is just a description of the implementation principle. In fact, this is not necessary.

Since we know that attribute and property are different, how can we tell whether an attribute belongs to attribute or property.
We can use in to judge property and hasAttribute to judge attribute.
However, ie6/7 does not have hasAttribute. Can it be determined only by in? By the way, hasAttribute is not required for ie6/7.
In ie6/7, attribute and property are not well distinguished. For example, run the following code in ie6/7:

<Div id = "t" tt = "1"> test </div>
<Script>
Var o = document. getElementById ('T ');
O ["tt"] = "2 ";
Document. writeln (o. getAttribute ("tt "));
Document. writeln (o ["tt"]);
O. setAttribute ("tt", "3 ");
Document. writeln (o. getAttribute ("tt "));
Document. writeln (o ["tt"]);
O ["rr"] = "4 ";
Document. writeln (o. getAttribute ("rr "));
Document. writeln (o ["rr"]);
Document. writeln (o. getAttribute ("innerHTML "));
Document. writeln (o ["innerHTML"]);
</Script>

As you can see, there is basically no attribute or property in it, and ie8 results except getAttribute ("innerHTML"), others are the same as ie6/7.
Of course, I think ie producers must know the difference between attribute and property, but they only get the results that users take for granted.
There was nothing wrong with being fooled like this, but then I found a problem:

<Div id = "t" class = "a"> test </div>
<Script>
Var o = document. getElementById ('T ');
O. setAttribute ("class", "B ");
Alert (o. outerHTML );
</Script>

The modified style is invalid. className is used according to ie rules, but the problem is that there are two class attributes in the div tag from outerHTML.
I have never known how to understand Internet Explorer before, but it has been corrected in Internet Explorer 8.
Attribute and property have been separated in ie8 (for details, see Attribute Differences in Internet Explorer 8 ).
For example, if getAttribute ("innerHTML") returns null, it indicates that innerHTML is no longer attribute; setAttribute ("class", x) modifies attribute, instead of adding an inexplicable class attribute to the dom element, it seems that getAttribute does not have the second parameter (the second parameter of getAttribute can be viewed here ).
However, ie8 still uses the mode of attribute and property when adding new attributes. It is estimated that it is to be compatible with the previous version.

Ps: [x] is used as an example, and the effect of the. operator is the same as that of [x.
Ps2: due to lack of deep understanding of dom, this part may be faulty.
Ps3: I found that I have little dom knowledge. I am looking for a dom book.


[Radio/checkbox checked status bug]

You can use ie6/7 to test the following code:
<Div id = "c">
<Input type = "checkbox" id = ""
/>
<Input name = "B" type = "radio" id = "B"
/>
</Div>
<Input type = "button" value = "click" id = "btn"
/>
<Script>
Var a = document. getElementById ("");
Var B = document. getElementById ("B ");
Var c = document. getElementById ("c ");
Document. getElementById ("btn"). onclick =
Function (){
C. appendChild ();
C. appendChild (B );
Var o1 = document. createElement ("input ");
O1.type =
"Checkbox"; o1.checked =
True;
C. appendChild (o1 );
Var o2 = document. createElement ("input ");
O2.type =
"Radio"; o2.checked =
True;
C. appendChild (o2 );
}
</Script>

Click checkbox and radio first, and then click the button. in ie6, the checkbox and radio are both restored to the unselected status. ie7 is better, but there is a problem with radio.
In addition, although the newly inserted checkbox and radio are both set to true, they are still unselected.
This is actually a problem. After some dom operations (such as appendChild) of checkbox and radio, the checked will automatically return to the defaultChecked state.
For details about how to create elements, refer to here.
In the program, tr will use appendChild to re-insert the document after sorting, and the result will cause the above problem. Three solutions can be found for the moment:
1. Modify defaultChecked before appendChild.
Appultchecked will be automatically restored for appendChild, so we will change defaultChecked to the current checked value before appendChild.
This solution is good, as long as the form control is scanned before appendChild, but the problem is that this will affect the reset results, because after the reset, the checked of checkbox/radio will be restored to the value of defaultChecked. If defacheckchecked is modified, the reset will lose effect.
2. Save the checked status before appendChild and restore it after appendChild.
There are two methods to achieve this. One is to use an array or object to save the current checked value of checkbox/radio, find the corresponding value after appendChild and set it.
The other is to directly Save the current checked value of checkbox/radio to a custom attribute of the control, and then obtain and set it after appendChild.
You need to scan the Form Control twice for both methods. The following method is more convenient.
3. Locate the controls whose checked is not the same as defaultChecked before appendChild, and reset these controls after appendChild.
This method is better than the previous one. You only need to scan the control before appendChild and filter out the items to be corrected (checked and defaultChecked are not equal ), after appendChild, set checked to the opposite value of defaultChecked.
The program uses 3rd methods. Before appendChild, use the GetChecked method to obtain the checkbox/radio set to be corrected:
GetChecked: function (){
This. _ checked = Filter (this. tBody. getElementsByTagName ("input"), function (o ){
Return (isIE6 & o. type =
"Checkbox") | o. type =
"Radio") & o. checked! = O. defaultChecked;
});
},

Use SetChecked to reset the checked value after appendChild:
SetChecked: function (){
ForEach (this. _ checked, function (o) {o. checked =
! O. defacheckchecked ;});
}

But the efficiency is still relatively low. If there is a better way, please tell me.


[Sorting object]

To make the program more flexible, add a sorting object.
This sorting object has the following attributes:
Default attribute value // description
Index: 0, // td Index
Attri: "innerHTML", // retrieves data attributes
DataType: "string", // data type for comparison
Desc: true, // whether to sort data in descending order
Compare: null, // custom sorting Function
StartSort: function () {}, // run before sorting
EndSort: function () {}// post-sorting execution

We can see that this sorting object is used to save the sorting rules and methods, that is, to tell the program how to sort.
This mode is used because a table usually requires multiple sorting methods at the same time. Using sorting objects is like selecting a boxing champion.
In a sorting process, the program can also set multiple sorting objects, one being KO (the comparison value is equal), and the other being on.
This method is more convenient and reusable.

In the program, the Creat program is used to create sorting objects. Its parameters are custom attributes:

Creat: function (options ){
Return Extend ({}, this. options), options || {});
}

Execute the Sort program to Sort, but one or more sorting objects must be parameters.
In the Sort program, the sorting object parameters are converted into Arrays:

Var orders = Array. prototype. slice. call (arguments );

Then it is passed to the Compare program. When the comparison result is 0 (equal) and the next sorting object exists, Compare will continue with the next sorting object:

Return! Result & orders [++ I]? This. Compare (orders, I, o1, o2): (order. Desc? -1: 1) * result;

In this way, the created sorting objects can be used to the maximum extent.


Usage

First, instantiate a primary sorting object. The parameter is the table id:

Var to = new TableOrder ("idTable ");

If you need to set the default attribute, we generally recommend that you set it when you are new.

Then, use the Creat method to add a sorting object. The parameter is the attribute object to be set (refer to [sorting object ]):

OdID = to. Creat ({DataType: "int", Desc: false })

Then, you can use the Sort method with the sorting object as the parameter for sorting:

To. Sort (order, odID );

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.