实现classList

博客先介绍数组特殊性、类数组对象概念及类数组调用数组方法的方式,接着阐述classList是可视化DOM实例属性,可操作类,但IE10以下不兼容。随后详细说明打造兼容所有浏览器的classList的步骤,包括添加自定义属性、定义构造器、添加功能及利用监听器同步,最后给出标准代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现classList前,先补充点知识

数组是特殊的对象,如何特殊?
  • 1.对象属性是数字(索引)
  • 2.有length属性
什么是类数组对象?
  • 1.具备数组的特征
  • 2.写法上跟数组一样,但不是数组,原型是Object。
类数组调用数组方法的方式
var o = {0: 'a', 1: 'b', 2: 'c', length: 3}
[].push.call(o, 'd')
对classList的理解

classList是所有可视化DOM实例的属性,也是用来设置DOM的类
classList属性的值是DOMTokenList类型,本质是一个集合对象,提供了add,remove,toggle等函数操作类

提示:classList属性对象可以轻松地完成jQuery对class相关的操作功能,但是IE10以下不兼容

接下来我们打造一个可以兼容所有浏览器的classList

第一步:如何给所有DOM元素都加上我们自己定义的neClassList属性

首先思考所有DOM元素继承于哪里

<div id="mydiv" class="classA classB classAB"></div>

我们可以通过constructor得到对象是由哪个构造器创建出来的

// HTML元素属于HTMLElement对象
console.log(mydiv.constructor) //ƒ HTMLDivElement() { [native code] }
// native code 本地代码,表示调用当前系统的底层API
console.log(mydiv instanceof HTMLElement) // true

可以得出HTMLElement是所有元素的祖先类,故在HTMLElement上定义neClassList属性

Object.defineProperty(HTMLElement.prototype, 'neClassList', {
    get: function () {
        // 当前元素没有NEDOMTokenList时创建NEDOMTokenList,有就直接访问
        if(!this.__dtl__) { //__dtl__自己创建的私有变量
            this.__dtl__ = new NEDOMTokenList(this.className.split(" "), this)// 将所有类名和dom传过去
        }
        return this.__dtl__
    }
})
第二步:定义构造器NEDOMTokenList
function NEDOMTokenList (classes, dom) {
    // 改造成类数组
    [].push.apply(this, classes)
}

可以通过console.log(mydiv.neClassList)验证
在这里插入图片描述

第三步:在原型链上添加我们想要的功能
NEDOMTokenList.prototype = {
	// 原型链的标准,构造器
    constructor: NEDOMTokenList, 
    // 添加元素
    add: function add(clazz) {
        if(this.contains(clazz)) return
        [].push.call(this, clazz)
    },
    // 移除元素
    remove: function remove(clazz) {
        for(var i = 0; i<this.length; i++) {
            if(clazz === this[i]) {
                [].splice.call(this, i, 1)
                return clazz
            }
        }
    },
    // 是否包含元素
    contains: function contains(clazz) {
        return [].includes.call(this, clazz)
    },
    // 切换元素
    toggle: function toggle(clazz) {
        this.contains(clazz) ? this.remove(clazz) : this.add(clazz)
    }
}

但我们发现一个问题,添加了classC后并没有同步HTML中

mydiv.neClassList.add('classC')

在这里插入图片描述

第四步:利用监听器进行同步
// 每次操作完后重新设置value
Object.defineProperty(this, 'value', {
    enomerable: false, // 设置私有变量不可枚举
    set: function (nv) {
        dom.className = nv
    }
})

再在每个方法后面添加this.value = [].join.call(this, ' '),如

add: function add(clazz) {
        if(this.contains(clazz)) return
        [].push.call(this, clazz)
        this.value = [].join.call(this, ' ')
    },

这样就能实现同步了
在这里插入图片描述
至此,实现了可以兼容所有浏览器的classList,最后,奉上标准的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="mydiv" class="classA classB classAB"></div>
    <script>
        function NEDOMTokenList (classes, dom) {
            // 改造成类数组
            [].push.apply(this, classes)
            // 监听器
            Object.defineProperty(this, 'value', {
                enomerable: false, // 设置私有变量不可枚举
                set: function (nv) {
                    dom.className = nv
                }
            })
        }
        // 类数组的属性方法
        NEDOMTokenList.prototype = Object.create(Array.prototype, { // 基于数组的功能上扩展
        	// 原型链的标准,构造器
            constructor: {
                value: NEDOMTokenList // value{}  编译器的规则
            },
            // 添加元素
            add: {
                value: function add(clazz) {
                    if(this.contains(clazz)) return // 若包含元素则不添加
                    [].push.call(this, clazz)
                    this.value = [].join.call(this, ' ')
                }
            },
            // 移除元素
            remove: {
                value: function remove(clazz) {
                    for(var i = 0; i<this.length; i++) {
                        if(clazz === this[i]) {
                            [].splice.call(this, i, 1)
                            return clazz
                        }
                    }
                    this.value = [].join.call(this, ' ')
                }
            },
            // 是否包含元素
            contains: {
                value: function contains(clazz) {
                    return [].includes.call(this, clazz)
                }
            },
            // 切换元素
            toggle: {
                value: function toggle(clazz) {
                    this.contains(clazz) ? this.remove(clazz) : this.add(clazz)
                    this.value = [].join.call(this, ' ')
                }
            }
        })

        Object.defineProperty(HTMLElement.prototype, 'neClassList', {
            get: function () {
                if(!this.__dtl__) {
                    this.__dtl__ = new NEDOMTokenList(this.className.split(" "), this)
                }
                return this.__dtl__
            }
        })
        mydiv.neClassList.add('classC')
        mydiv.neClassList.add('classA')
        mydiv.neClassList.remove('classA')
        mydiv.neClassList.add('classA')
        console.log(mydiv.neClassList)
        console.log(mydiv.neClassList.contains('classAB'))
    </script>
</body>
</html>
### JavaScript `classList` 方法使用说明 #### 基本概念 `classList` 是 DOM 元素的一个属性,它返回一个类似数组的对象,包含了该元素所有的 CSS 类名。通过这个对象可以方便地操作元素的类名集合。 #### 主要方法 以下是 `classList` 提供的主要方法及其功能: 1. **添加类名** 使用 `add()` 方法向指定元素添加一个新的 CSS 类名。 ```javascript const element = document.querySelector('.demo'); element.classList.add('new-class'); // 向 .demo 添加 new-class 类名 ``` 2. **移除类名** 使用 `remove()` 方法从指定元素中移除已有的 CSS 类名。 ```javascript const element = document.querySelector('.demo'); element.classList.remove('old-class'); // 移除 old-class 类名 ``` 3. **切换类名** 使用 `toggle()` 方法可以在存在时移除某个类名,在不存在时添加该类名。 ```javascript const element = document.querySelector('.demo'); element.classList.toggle('active'); // 如果 active 存在则移除,如果不存在则添加 ``` 4. **检查是否存在某类名** 使用 `contains()` 方法判断当前元素是否包含特定的类名,返回布尔值。 ```javascript const element = document.querySelector('.demo'); console.log(element.classList.contains('active')); // 返回 true 或 false ``` 5. **替换类名** 使用 `replace()` 方法可以用新的类名替代现有的类名(适用于现代浏览器)。 ```javascript const element = document.querySelector('.demo'); element.classList.replace('old-class', 'new-class'); // 将 old-class 替换为 new-class ``` #### 实际应用案例 下面是一个综合使用的例子,展示如何动态控制页面样式: ```html <div id="myElement">Hello</div> <style> .highlight { color: red; font-weight: bold; } </style> <script> const element = document.getElementById("myElement"); // 添加高亮类名 element.classList.add("highlight"); // 检查是否有 highligh 类名 if (element.classList.contains("highlight")) { console.log("Highlight class is present."); } // 切换 highlight 类名 setTimeout(() => { element.classList.toggle("highlight"); }, 2000); </script> ``` 上述代码展示了如何利用 `classList` 动态修改 HTML 元素的样式[^1]。 --- #### 注意事项 - 调用 `classList` 的前提是目标元素已经存在于文档中。 - 对于不支持 `classList` 的旧版浏览器,可以通过直接操作 `className` 属性实现类似的逻辑[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

callmeCassie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值