摘要:基于某些考虑,有时我们项目中会尽量使用原生,这种情况下连最简单的类选择器可能都要进行兼容性处理。越是新的特性,浏览器的兼容相对就越差。但原生的是支持多个类名选择的,既然要写一个兼容的自定义类选择器代替原生的,那么这个功能说什么也要上啊。
基于某些考虑,有时我们项目中会尽量使用原生js,这种情况下连最简单的类选择器可能都要进行兼容性处理。getElementsByClassName是后来引入的,历史不如getElementById和getElementsByTagName。越是新的特性,浏览器的兼容相对就越差。
虽然这3个选择器都并不是百分百兼容所有浏览器,比如getElementById和getElementsByTagName在IE上只支持>=5.5,不过谁还用低于5.5的IE呢?但getElementsByClassName就不同了,它在IE上只支持>=9,所以就存在兼容性的问题。
兼容的方式,就是利用getElementsByTagName来获取所有的标签,然后判断每个标签有没有class,以及class里面的值是不是等于我们要找的。《JavaScript DOM编程艺术(第2版)》第42页有一个简单实现,但因为作者只是想说明原理,所以没有完善,用了indexOf去判断我们要的类名在不在标签的类名中,这会导致假如我们要找nam的话会把类名叫name的都找出来。所以网上有很多的实现,大致如下,并且下面的实现还考虑了标签的类名可能有多个类的情况。
zero
one
two
three
- function getElementsByClassName(node, className){
- // 如果支持原生getElementsByClassName就直接使用并返回结果
- if (node.getElementsByClassName){
- return node.getElementsByClassName(className);
- }
- // 这是最终返回的结果数组
- var results = new Array();
- // 先获取node节点下所有的标签
- var elements = node.getElementsByTagName("*");
- // 循环遍历获得的所有标签
- for (var i = 0; i < elements.length; i++){
- // 获取循环中的标签
- var ele = elements[i];
- // 获取该标签的类名
- var cName = ele.className;
- // 如果类名为空,也就是没有class,那么这个标签肯定不是,所以继续循环下一次标签
- if (cName === ""){
- continue;
- }
- // 如果是多个class,那么就分别获得这几个class
- var cNames = cName.split(" ");
- // 循环遍历标签中的几个class,只要有一个class和我们要的className相等,说明就是匹配的标签
- for (var j = 0; j < cNames.length; j++){
- if (cNames[j] === className){
- results[results.length] = ele;
- break;
- }
- }
- }
- return results;
- }
- // 使用自定义的类选择器
- var nodes = getElementsByClassName(document.getElementById("app"), "name-three");
- for (var i = 0; i < nodes.length; i++){
- console.log(nodes[i].innerText);
- }
如果在网络上找类似的实现的话,基本上就是到上面这一步。但上面的实现仍然存在一个缺陷,比如要选择类名既包括name又包括name-three的标签就没法实现。
</>code
var nodes = getElementsByClassName(document.getElementById("app"), "name name-three");
但原生的getElementsByClassName是支持多个类名选择的,既然要写一个兼容的自定义类选择器代替原生的,那么这个功能说什么也要上啊。和上面的变化,主要在于我们不仅要处理每个标签可能有多个类名的情况,也要处理我们传入的类名参数可能也是多个类名组成的情况,所以用两层循环可以实现,这里只给出与上面不同的代码部分。
</>code
// 标签:如果是多个class,那么就分别获得这几个class
var cNames = cName.split(" ");
// 我们要找的类名:如果是多个class,那么就分别获得这几个class
var classNames = className.split(" ");
// 设置一个标记,默认为true,如果在循环判断中发现有条件不满足,设置为false
var flag = true;
// 先循环我们要找的每一个类名
for (var j = 0; j < classNames.length && flag; j++){
// 看看我们的这个类名在不在这个标签的所有类名中
for (var k = 0; k < cNames.length; k++){
if (classNames[j] === cNames[k]){
break;
}else if(classNames[j] !== cName[k] && k === cNames.length - 1){
// 循环到标签最后一个类名了,还不相等,就说明不匹配
flag = false;
break;
}
}
}
// 如果符合条件,就加入结果集然后返回
if (flag){
results[results.length] = ele;
}
至此,就可以用我们自定义的类选择器查找多个类都匹配的标签了。如果还要完善的话,至少还需要判断用户传入的类名参数是否为空这种情况。
如果还要加强功能的话,可以考虑实现一个多级选择器的功能,比如jQuery中如下的语句,甚至还可以优化循环遍历的写法等。
</>code
// 选择id为app下的所有class名有name的标签
$("#app .name")
实现一个功能简单,做成一个产品很难。不过话说回来,如果要自定义太复杂的功能,我们当初在选择原生js时就会更加慎重了。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/109288.html
摘要:节点的类型有很多,常用的主要是三种元素节点属性节点和文本节点。结果如下和,前者是获取某个属性值,后者才是获取属性节点。 js在处理DOM的时候,文档中的内容都会被当成一个个节点,也就是常说的node。节点的类型有很多,常用的主要是三种:元素节点、属性节点和文本节点。 元素相当于我们说的标签,属性就是标签中定义的属性,文本就是标签里面的文字。比如下面我们可以通过getElementByI...
摘要:前言前几天知乎上有一个问题真的过时了吗我的答案是确实过时了感觉这个话题挺有趣,那咱们展开了聊聊。详细地说一下为什么过时了。天猫去年已经宣布不再支持。三并没有被淘汰虽然已经过时了,但是并没有被淘汰,而且近几年也不会。 前言 前几天知乎上有一个问题:jQuery真的过时了吗?我的答案是:jQuery确实过时了!感觉这个话题挺有趣,那咱们展开了聊聊。详细地说一下jQuery为什么过时了。 一...
摘要:前端技术之详解第二天华文中宋基础选择器负责结构,负责样式,负责行为。微软雅黑浏览器的市场占有率浏览器打分儿子选择器测试工具的儿子。表示选择下一个兄弟微软雅黑选择上的是元素后面紧挨着的第一个兄弟。前端技术之_CSS详解第二天 1、css基础选择器 html负责结构,css负责样式,js负责行为。 css写在head标签里面,容器style标签。 先写选择器,然后写大括号,大括号里面是样式。 ...
摘要:去掉了对的支持,并使用和单位。更新了所有伪元素选择器的使用规范,首选双冒号如,而不是。卡片现在有不同的轮廓和进一步支持基于类的扩展。代表水平方向,代表全部。 Bootstrap 这个号称世界第一的 responsive 和 mobile first 前端样式组件库去年八月发布了 v4.0 Alpha,去年年底时发布了 v4.0 Alpha 2 版本。可能是 v3 用的过于顺手,直到今天...
阅读 1273·2023-04-26 00:12
阅读 3529·2021-11-17 09:33
阅读 1194·2021-09-04 16:45
阅读 1354·2021-09-02 15:40
阅读 2466·2019-08-30 15:56
阅读 3169·2019-08-30 15:53
阅读 3681·2019-08-30 11:23
阅读 2074·2019-08-29 13:54