[Original] jquery source code analysis-13 CSS operations-CSS-class style-addclass + removeclass + toggleclass + hasclass

Source: Internet
Author: User
Tags rtrim

Author: nuysoft/high cloud QQ: 47214707 Email: nuysoft@gmail.com
Disclaimer: This article is an original article. If you need to reprint it, please indicate the source and retain the original article link.

Jquery source code analysis series (Continuous updates)

 

Class Style

 

Overview

. Addclass ()

. Removeclass ()

. Toggleclass ()

. Hasclass ()

 

Overview

 

During development, I occasionally need to operate style sheets. Most of them are operational styles. Javascript is responsible for data, business logic, and interaction. CSS is responsible for presenting results and performing their respective duties as much as possible, reduce the coupling between JavaScript and CSS to facilitate maintenance.

Jquery provides four methods to operate classes:

Jquery. FN. extend ({//... // Add the specified class (es) addclass: function (value) {}for each matching element, // from each matching element, remove one or more classremoveclass: function (value) {}, // add or delete one or more classtoggleclass: function (value, stateval) {}, // check whether the matched element specifies the passed class. If there is a match, truehasclass: function (selector) {}, //...}) is returned ){},//...});

The Core Technique of implementation is to add spaces before and use indexof to find the class style position or use replace to delete the class style.It is very concise and practical and worth learning.

Compared with the operating style table, it must be compatible with browser differences, DOM/html style attributes, and some special bugs. The implementation of operating style is more elegant and regular. Start learning one by one.

 

. Addclass ()

 

. Addclass ()Add the specified class (es) for each element to match), You can add multiple classes at a time ;. addclass () does not replace the existing class attribute values. It is just a simple append. Duplicate classes are filtered and not repeatedly appended (may not be filtered before 1.6.2). Starting from jquery1.4 ,. addclass () supports functions as parameters.

Code Execution Process OverviewAs follows:

If it is a function, execute the function and call. addclass () again to return the result ()

If it is a string

If the classname is null and only one classname is input, the value is directly assigned to ELEM. classname.

Otherwise, a space is added before and after ELEM. classname and classnames [c] to determine whether to ignore or append the returned value of indexof.

Core Skills: Add a space + indexof to the front and back. For more information, see.Source code analysis:

/*** Add the specified class (es) for each Matching Element )*. addclass (classname) * classname is added to one or more classes on the class attribute of each Matching Element **. addclass (function (index, currentclass) * function (index, currentclass) returns one or more class names. Multiple classes are separated by spaces, these classes are added to the existing class attribute * the position of the current index element in the Set, the current class name of currentclass, this points to the current element of the Set * Core tips: add spaces + indexof */addclass: function (value) {/** starting from 1.6.2. These local variables are extracted to the method header, which seems like jquery has always been using: constantly refactoring Code * I personally am An obvious reason against this concentrated definition of variables is: * When I read down a variable that I did not understand, I need to jump to the method header to understand and verify it, then I will jump back to */var classnames, I, L, ELEM, setclass, C, Cl; // If the input function is used, execute the function and take the return value as the classnamesif (jquery. isfunction (value) {return this. each (function (j) {/** iterative call * will create var self = jquery (this) in versions earlier than 1.6.2; * through self. ATTR ("class") | "" Get the current class value * starting from 1.6.2, use this. classname to get * slightly improves performance, but why did we call ATTR before? Not understanding ** note that there is no jquery. addclass function, * actually used. addclass () calls jquery. addclass () can avoid creating a new jquery object * possibly creating a jquery. addclass, and then there are few places to reuse, all in jquery. FN. addclass implements */jquery (this ). addclass (value. call (this, J, this. classname);} // if the value is a string, you can see it. addclass () only accepts strings and functions if (Value & typeof value = "string") {classnames = value. split (rspace); // use a blank space to split classnames and convert it to an array for (I = 0, L = This. length; I <L; I ++) {// traverses all matching elements, and the cache length is lengthelem = This [I]; // cached to avoid re-searching if (ELEM. nodetype = 1) {// element/** if the class attribute is not specified in HTML, or the class attribute is a null string * adds the judgment condition classnames starting from 1.6.2. length = 1, more than one Div whose class needs to be de-duplicated * 1.6.2 before the length of classnames is not judged, that is, there is no de-duplicated ** test in chrome15 and no class is specified, its classname returns an empty string "" */If (! ELEM. classname & classnames. length = 1) {ELEM. classname = value; // The length of the existing classname or classnames is greater than 1} else {/** plus spaces. You can use indexof to determine whether to use ELEM first. classname is retrieved and cached, and then assigned a value at a time after assembly * avoid the browser rendering multiple times due to multiple classname modifications */setclass = "" + ELEM. classname + ""; for (C = 0, CL = classnames. length; C <CL; C ++) {/** about ~, From JavaScript authoritative guide 5th * ~ Bitwise non-operator ,~ Is a unary operator. It is located before an integer parameter and returns all bits of the number of operations. * It is equivalent to changing its symbol and subtracting one. * In fact, you can simply judge the return value of indexof. If the value is smaller than 0, it indicates that * does not exist. If the value is smaller than 0, append the value to setclass and ** test :*~ -1 = 0 ;~ 0 =-1 ;~ 1 = 2 ;~ 2 =-3 *!~ -1 = true ;!~ 0 = FASE ;!~ 1 = false ;~ 2 = false ** so the if judgment logic is: no (-1) returns true. In other cases, false * is returned. * starting from 1.6.2, this is cool; you can't help but want to test and verify it: * <PRE> * var COUNT = 100000; * console. time ('1yua'); for (I = 0; I <count; I ++ )! ~ -1; console. timeend ('1yuanyuan ') * console. time ('2yua'); for (I = 0; I <count; I ++) 1 <-1; console. timeend ('2yuan ') * </PRE> * this case is very simple. We have repeatedly computed and adjusted the sequence operation in the test case, and have not found that the unary operator is faster than the binary operator! * Mining is pending! John resig was joking. It cannot be ruled out that John resig may be naughty occasionally! */If (!~ Setclass. indexof ("" + classnames [c] + "") {setclass + = classnames [c] + ""; // append, add a space}/** to remove the leading and trailing space characters * trim to divide the replacement process into two steps: replacing the leading space character and replacing the trailing space character * In fact, except in trim, I have not found any other code. trimleft trimright * is used. If efficiency is considered, it is faster to merge them together * rtrim =/^ \ s + | \ s + $/; * text. tostring (). replace (rtrim, ""); * this separation may be for potential reuse * So performance is not the only pursuit, this is the trade-off between John resig's readability, granularity, and performance. */ELEM. classname = jquery. trim (setclass) ;}}} return this ;},

 

. Removeclass ()

 

. Removeclass ()Removes one or more or all classes from each matching element.If a class parameter is input, only this class will be removed; if no parameter is specified, all classes will be removed; multiple classes can be removed at a time, multiple classes are separated by spaces. This method is often used. addclass can be used together to change the class of an element from one to another. If you want to replace all existing classes with one class, you can use it. ATTR ('class', 'newclass'); Starting from jquery1.4 ,. the removeclass () method supports passing in a function as a parameter.

Code Execution Process OverviewAs follows:

If it is a function, execute the function and call jquery. FN. removeclass again to return the result.

If it is a string, add a space before and after ELEM. classname and classnames [c] to determine whether replace is deleted.

If it is undefined, set it to an empty string ELEM. classname = ""

Core Skills: Add a space + replace to the front and back. For more information, see.Source code analysis:

/*** Remove one or more classes from each Matching Element **. removeclass ([classname]) * classname one or more classes separated by spaces, these classes will be exceeded from the class attribute of the matching element **. removeclass (function (index, class) * function (index, class) returns one or more classes separated by spaces for removal. * The position of the current index element in the matched element set. The old class value of the class * Core Skills: Adding spaces + replace */removeclass: function (value) {var classnames, I, l, ELEM, classname, C, Cl; // If a function is input, the system executes the function. The returned value is used as the classnamesif (jquery. isfunction (value) {return this. each (function (j) {// iterative call, see. addclass () annotation jquery (this ). removeclass (value. call (this, J, this. classname);}/** comparison. addclass () condition: If (Value & typeof value = "string") * From here we can see. removeclass () supports the following parameter types: * Function Iteration Processing * non-null string removal * undefined all removal * Note: empty strings are not processed. */If (Value & typeof value = "string") | value = undefined) {classnames = (value | ""). split (rspace); // split into arrays // value | "" common tips for avoiding null reference errors (referenceerror: value is undefined) for (I = 0, L = This. length; I <L; I ++) {// traverse matched elements, cache set length ELEM = This [I]; // element, and has the classname attribute, if (ELEM. nodetype = 1 & ELEM. classname) {// if there is a value, delete if (value) {classname = ("" + ELEM. classname + ""). replace (rclass, ""); // Add spaces before and after replacement to replace \ n \ t \ r with spaces for (C = 0, CL = classnames. length; C <CL; C ++) {classname = classname. replace ("" + classnames [c] + "", ""); // Replace the classname to be deleted with a space} // Delete the leading and trailing spaces, and assign the value to ELEM. classnameelem. classname = jquery. trim (classname); // No value undefined is specified, clear the classname attribute} else {// clear ELEM. classname = "" ;}}} return this ;},

 

. Toggleclass ()

 

. Toggleclass ()Adds or deletes one or more classes for each element in the matched element set. The added or deleted behavior depends on whether the current element contains the specified class or switch parameter value.;. Toggleclass () accepts one or more classes; if not. if toggleclass () is specified, all class names on the element will be switched. Since jquery1.4, classname can be a function, and the return value of the function is used as the classname for switching.

Code Execution Process OverviewAs follows:

If it is a function, execute the function and use the return value of the function as the classname for switching. Call jquery. FN. toggleclass iteratively.

Traverse the current jquery object

If the value is a string and the class style in the value is traversed one by one, switch has a higher priority than hasclass. If hasclass returns false, addclass returns true, then removeclass

If no parameter is specified or only a switch exists, the entire classname is switched.

Core Skills: Call addclass or removeclass or assign ELEM. classname directly.

Pay attention: Found during source code readingSwitchThe functions are inconsistent in different parameter environments .. Toggleclass () is used in four ways (For details, refer to the source code comment below ):

1  .toggleClass( className ) 1.02  .toggleClass( className, switch ) 1.33  .toggleClass( [switch] ) 1.44  .toggleClass( function(index, class, switch) [, switch] ) 1.4

In versions 2 and 4, the switch determines whether to add (true) or delete (false). For example:

$ ('# Foo '). toggleclass (classname, addorremove); // essentially equivalent to: If (addorremove) $ ('# foo '). addclass (classname); else $ ('# foo '). removeclass (classname );

HoweverIn 3, if switch is true, all normal switches are performed, which is equivalent to undefined. If switch is false, it is always null.; In fact, thisNot mentioned in the official API. This logic is embodied in the ternary expression of the last line.

DetailsSource code analysis(In terms of code skills, I thinkThe most subtle is the last line of code):

/*** Add or delete one or more classes to or from each element in the matched element set * depending on whether the current element contains the specified class, or Switch Parameter Value **. toggleclass (classname) 1.0 * classname one or more classes (separated by spaces), switching class on each element matching the Element Set * If an element in the set contains the specified classname, classname will be deleted; if not, it will be added. **. Toggleclass (classname, switch) 1.3 * Switch A boolean value. Based on this Boolean value, it is determined whether to add (true) or delete (false )**. toggleclass ([Switch]) 1.4 * Switch A boolean value. Based on this Boolean value, you can determine whether to add or delete the value **. toggleclass (function (index, class, switch) [, switch]) 1.4 * function (index, class, switch) function return the calss name used for switching * index indicates that the current element is the subscript position in the set, and the class is the current element's class value. ** core tips: Call addclass or removeclass or directly assign a value to ELEM. classname */toggleclass: function (value, stat Eval) {var type = typeof value, // value type, which can be a string (one or more classes) or a function (undefined or Boolean) isbool = typeof stateval = "Boolean"; // if it is a function, the system executes the function and uses the return value of the function as the classname to call jquery iteratively. FN. toggleclassif (jquery. isfunction (value) {return this. each (function (I) {// call jquery (this) iteratively ). toggleclass (value. call (this, I, this. classname, stateval), stateval) ;}; // traverses the current jquery object return this. each (fun Ction () {// value is a string that traverses the class style in value one by one. The switch has a higher priority than hasclass, if hasclass returns false, addclass returns true, removeclassif (type = "string") {// toggle individual class names // switch a single classvar classname, I = 0, self = jquery (this), State = stateval, classnames = value. split (rspace); // There may be multiple classes, separated by a blank space. // This does not require spaces before and after classname, so here we can combine values, auto-increment, and judgment into a while loop. Good skills. While (classname = classnames [I ++]) {// check each classname given, space seperated list/** if the State is a Boolean value, the State prevails, otherwise, check whether the classname * contains "state" to "false", indicating that addclass is required. Otherwise, the "removeclass *" ternary expression combines state with self. tips for judging hasclass */State = isbool? State :! Self. hasclass (classname); self [State? "Addclass": "removeclass"] (classname);}/** type = "undefined" unspecified parameter, that is. toggleclass () * type = "Boolean" Omitting classname, only switch, that is. toggleclass (switch) * // if no parameter is specified or only a switch exists, switch the entire classname} else if (type = "undefined" | type = "Boolean ") {// If classname exists, it is cached so that if (this. classname) {// store classname if set // cache jquery using internal data. _ data (this, "_ classname _", this. classname );}// Toggle whole classname/** switching the entire classname * is a three element that combines several judgment conditions and is divided into four Logics: * this. classname & value is true/undefined "" * This. classname & value is false ""*! This. classname & value is true/undefinedjquery. _ data (this, "_ classname _") | ""*! This. classname & value is false "" ** analyze the above four logics, which can be summarized as follows: (value is replaced by SWITCH) * 1. if this. classname exists. No matter what status of the switch (true/false/undefined), it is set to null "" * 2. if this. classname does not exist. If the switch is true/undefined, The classname * 3 will be restored. if this. classname does not exist. If switch is false, leave it blank (unchanged )**. toggleclass (switch) usage can be summarized as follows: * 1. if the switch value is true, the switch is normal, which is equivalent. toggleclass () * 2. if switch is false, it is always empty. ** it is very delicate and cool at first! */This. classname = This. classname | value = false? "": Jquery. _ data (this, "_ classname _") | "";}});},

 

. Hasclass ()

 

. Hasclass ()Checks whether the matched element specifies the passed class. If there is a match, true is returned.The element may have multiple classes. Multiple classes in HTML are separated by spaces. If an element contains the specified classname ,. hasclass () returns true, even if other classname is specified.

Note:

1.If selector comes with leading/trailing SpacesIn fact, the front and back spaces can be filtered and then detected. In this way, the code is more flexible when classname is detected dynamically.

2.Selector can contain multiple class styles, but is not split into arrays but used as an overall detection.For example, the following situations cannot return the correct results:

$ ('Div '). addclass ('1 2 3'). hasclass ('1 3') // false

Core Skills: Add space + indexof

Source code analysis:

/*** Checks whether the matched element specifies the passed class. If there is a match, true * is returned *. hasclass (classname) * classname class * Core tips: Add spaces + indexof */hasclass: function (selector) {var classname = "" + selector + "", // Add spaces I = 0, L = This. length; For (; I <L; I ++) {// it must be an element. The technique is to add spaces before and after the element, and indexofif (this [I]. nodetype = 1 & ("" + this [I]. classname + ""). replace (rclass ,""). indexof (classname)>-1) {return true ;}} return false ;},
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.