For js, I think everyone who is new to it should complain: why there is no way to get elements through class. Although higher versions of browsers now support the getElementsByClassName() function, it is still incompatible for lower versions of browsers. When leaving other libraries, you still have to encapsulate a method yourself.
Method 1
function getByClass1(parent, cls){ var res = []; //Array that stores matching results var ele = parent.getElementsByTagName('*'); for(var i = 0; i < ele.length; i++){ if(ele[i].className == cls){ res.push(ele[i]); } } return res;}Of course, when there is only one value in the class, the above method is fine, but when there are multiple values, problems will arise.
<div></div><div></div><script> getByClass1(document, 'test'); // Get only the first div</script>
Method 2
When problems arise, we will try to improve. For multi-class names, we can use regular matching to see if the class name is included, so the following writing method appears:
function getByClass2(parent, cls){ var res = []; var reg = new RegExp('//b' + cls + '//b', 'i'); //Match cls is an independent word var ele = parent.getElementsByTagName('*'); for(var i = 0; i < ele.length; i++){ if(reg.test(ele[i].className)){ res.push(ele[i]); } } return res;}This method seems to be OK and solved the problem of getByClass1(). I have used it for a long time, but there is still a hidden bug. See the following example:
<div></div><div></div><div></div><script> getByClass2(document, 'test'); //The result is the first div and the third div</script>
In theory, we should only get the first one, but it is different from what we expected. This bug originates from /b in the following code
var reg = new RegExp('//b' + cls + '//b', 'i');Let's first look at the meaning of /b in the regular
/b is a special code specified by a regular expression, representing the beginning or end of a word, that is, the boundary of a word.
To put it simply: /b is to match a word (from the left border to the right border).
The problem lies here. /b regards all other characters except letters, numbers, and underscores as boundaries. For the above example, the third class value is test-box. When /b matches, the hyphen (-) is regarded as the word boundary, so it also matches the third div.
Method 3
Therefore, we need to make further improvements to the above method. Here we refer to a method mentioned on stackoverflow:
How to Get Element By Class in JavaScript?
The improved code is as follows:
function getByClass3(parent, cls){ var res = []; var reg = new RegExp(' ' + cls + ' ', 'i'); //When matching cls, there need to be spaces on both sides var ele = parent.getElementsByTagName('*'); for(var i = 0; i < ele.length; i++){ if(reg.test(' ' + ele[i].className + ' ')){ res.push(ele[i]); } } return res;}This method abandons the use of /b and uses spaces to match the boundaries. First add spaces to both sides of the obtained className value, which ensures that there will be spaces on both sides of each value in className, and then use regular to match.
No problem has been found using this method yet, but when using it, the spaces in single quotes in the method must not be dropped.
Method 4
function getByClass3(parent, cls){ var res = []; var reg = new RegExp('(^|//s)' + cls + '($|//s)', 'i'); var ele = parent.getElementsByTagName('*'); for(var i = 0; i < ele.length; i++){ if(reg.test(ele[i].className)){ res.push(ele[i]); } } return res;}Spaces are completely handled with regularity, which eliminates the problem of easy spaces falling and the code is more beautiful and simple.
So is this method relatively perfect? In fact, it is not. Let’s take a look at a better solution.
Method 5 (Perfect Edition)
As mentioned at the beginning of the article, higher versions of browsers already support the getElementsByClassName() method. For performance reasons, it is bound to be better to use native methods for supported browsers. For lower versions of browsers, use the above method four.
function getByClass(parent, cls){ if(parent.getElementsByClassName){ return parent.getElementsByClassName(cls); }else{ var res = []; var reg = new RegExp(' ' + cls + ' ', 'i') var ele = parent.getElementsByTagName('*'); for(var i = 0; i < ele.length; i++){ if(reg.test(' ' + ele[i].className + ' ')){ res.push(ele[i]); } } return res; }}Of course, method 5 is considered a relatively good solution. If there is a better method, please leave a message to add it.