从 classList 到 DOMTokenList: 简化类名管理的工具

ops/2024/11/2 15:35:48/
webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

引言

在现代的网页开发中, 与用户界面交互的核心是操作和控制 DOM。 其中, 处理元素的外观和交互是不可或缺的一个环节, 而其中 classListDOMTokenList 作为一个强大工具, 为开发人员提供了便捷的方式来管理 DOM 元素的类名。

在这篇文章中, 我们将简单梳理下 classListDOMTokenList 之间的关系, 以及对应的一些基础属性和方法!!! 知道这些内容后, 有助于我们更好的处理、管理类名!!!

一、classList 属性

Element.classListDOM 对象上的一个只读属性, 该属性返回一个元素的 class 属性集合, 该值实现了 DOMTokenList 接口(关于 DOMTokenList 接口下文会进行详细的介绍)

image

作用: 通过 classList 我们可以很方便针对元素 className 进行增、删、改、查、遍历等一些列操作, 并且相比于将 element.className 作为以空格分隔的字符串来进行操作, 通过 classList 进行处理无疑是更为方便、灵活的!

const div = document.createElement("div");
div.className = "foo";// 初始状态:<div class="foo"></div>
console.log(div.outerHTML);// 使用 classList API 移除、添加类值
div.classList.remove("foo");
div.classList.add("anotherclass");// <div class="anotherclass"></div>
console.log(div.outerHTML);// 如果 visible 类值已存在,则移除它,否则添加它
div.classList.toggle("visible");// add/remove visible, depending on test conditional, i less than 10
div.classList.toggle("visible", i < 10);console.log(div.classList.contains("foo"));// 添加或移除多个类值
div.classList.add("foo", "bar", "baz");
div.classList.remove("foo", "bar", "baz");// 使用展开语法添加或移除多个类值
const cls = ["foo", "bar"];
div.classList.add(...cls);
div.classList.remove(...cls);// 将类值 "foo" 替换成 "bar"
div.classList.replace("foo", "bar");

这里我们只需要知道 classListDOMTokenList 接口的实现, 至于它有哪些方法、属性, 下面我们来慢慢讲解

二、DOMTokenList 概述

DOMTokenList 接口用于表示一组由 空格分隔字符串 合集, 它最常以 Element.prototype.classList 属性的形式被使用, 如上文所示

2.1 数据结构

下面我们尝试打印下选中节点的 classList 属性, 来简单过下 DOMTokenList 对象的一个格式

补充: 在 chrome 控制台中 $0 是有特殊含义的, 表示当前选中的 DOM 节点

image

image

从上图可以看出, DOMTokenList 对象是一个 类数组 对象, 每个值都有一个对应的索引(从 0 开始), 同时具有 length 以及 value 属性, 以及多个方法实例方法, 下面我们来简单介绍下这些属性、方法

2.2 创建实例

我们可以尝试使用 new 创建一个 DOMTokenList 实例, 你会发现这么做将会报错(因为它是不允许被手动实例化的)

image

既然无法直接进行实例化, 那是不是就无法手动创建 DOMTokenList 实例呢? 其实不是的, 我们可以创建一个工具函数, 通过创建 DOM 的方式来间接创建 DOMTokenList 实例, 如下代码所示:

const createDOMTokenList = (value) => {const div = document.createElement("div");if (value) {div.className = value;}return div.classList
}

2.3 两个属性

  1. length: 上文提到 DOMTokenList 接口实现了一个 类数组 对象, 那么它必然会有一个 length 属性, 返回当前 类数组 的一个长度
const list = createDOMTokenList('foo wrapper main bar')
console.log(list.length) // 4
  1. value: DOMTokenList 接口返回的 类数组, 它的每一项值实际上是将 原始值 通过空格拆分后的结果, 那么 value 这个属性值可以帮助我们获取到未拆分的一个原始值
const list = createDOMTokenList('foo wrapper main bar')
console.log(list.value) // foo wrapper main bar

2.4 增删改查

  1. 增: 可通过 DOMTokenList.add(token1[, token2[, ...tokenN]]) 方法, 新增一个或多个 token
const list = createDOMTokenList('foo wrapper main bar')
list.add('a', 'b', 'c', 'd')
console.log(list.value) // foo wrapper main bar a b c d
  1. 删: 可通过 DOMTokenList.remove(token1[, token2[, ...tokenN]]) 方法, 删除一个或多个 token
const list = createDOMTokenList('foo wrapper main bar')
list.remove('wrapper', 'bar', 'a')
console.log(list.value) // foo main
  1. 替换: 可通过 DOMTokenList.replace(oldToken, newToken), 将 oldToken 替换为 newToken, 替换成功返回 true, 否则返回 false
const list = createDOMTokenList('foo wrapper main bar')
list.replace('wrapper', 'a') // true
console.log(list.value) // foo a main barlist.replace('fo', 'f') // false
console.log(list.value) // foo a main bar
  1. 切换: 可通过 DOMTokenList.toggle(token [, force]) 来切换(来回添加隐藏)指定 token
  1. 不设置第二参数 force 的情况下, 如果存在指定 token 则移除并返回 false, 如果不存在则添加并返回 true
  2. 如果第二参数 force 设置为 true, 则表示强制设置指定 toekn, 如果存在则直接返回 true, 如果不存在则添加并返回 true
  3. 如果第二参数 force 设置为 false, 则表示强制隐藏指定 toekn, 如果存在则隐藏并返回 false, 如果不存在则直接返回 false
  4. 补充: 该方法返回值表示, 操作完后, 是否还存在指定 toekn
const list = createDOMTokenList('foo wrapper main bar')
list.toggle('main') // false
list // DOMTokenList(3) ['foo', 'wrapper', 'bar']
list.toggle('main') // true
list // DOMTokenList(4) ['foo', 'wrapper', 'bar', 'main']list.toggle('main', true) // true
list // DOMTokenList(4) ['foo', 'wrapper', 'bar', 'main']
list.toggle('main2', true) // true
list // DOMTokenList(5) ['foo', 'wrapper', 'bar', 'main', 'main2']list.toggle('main3', false) // false
list // DOMTokenList(5) ['foo', 'wrapper', 'bar', 'main', 'main2']
list.toggle('main2', false) // false
list // DOMTokenList(5) ['foo', 'wrapper', 'bar', 'main']
  1. 查: 可通过 DOMTokenList.item(index) 或者指定索引位置的 token
const list = createDOMTokenList('foo wrapper main bar')
list.item(0) // foo
list.item(2) // main
  1. 查: 可通过 DOMTokenList.contains(token) 来判断指定 token 是否存在于列表中, 如果存在则返回 true 否则返回 false
const list = createDOMTokenList('foo wrapper main bar')
list.contains('main') // true
list.contains('body') // false

2.5 循环

  1. 使用 forEach 进行循环: 通过 DOMTokenList.forEach(callback [, thisArg]) 来遍历 token, 该方法参数同 Array.forEach
const list = createDOMTokenList('foo wrapper main bar')list.forEach((current, index, origin) => {console.log('current: ', current)console.log('index: ', index)console.log('origin: ', origin)
})

image

  1. 先获取值, 然后再循环: 同 Array 可通过 DOMTokenList.keys()DOMTokenList.values()DOMTokenList.entries() 等方法获取到索引、或者值的一个集合, 然后进行遍历

需要注意的是, 这几个方法返回的值都是一个迭代器, 关于迭代器的知识可查阅 《迭代器、生成器详解🔥🔥🔥》

const list = createDOMTokenList('foo wrapper main bar')[...list.keys()].forEach(v => {console.log(v) // 0 1 2 3
})[...list.values()].forEach(v => {console.log(v) // foo wrapper main bar
})[...list.entries()].forEach(v => {console.log(v) // [0, foo] [1, wrapper] [2, main] [3, bar]
})

2.6 非空

对于 addremovereplacetoggle 这几个需要输入 token 并且会修改列表的方法, 如果 token空字符串 将会报错(传 null 或者 undefined 是不会报错的)

image

2.7 去重(空格、token)

  1. 对于 add 以及 remove 方法只要执行了, 就会去除重复的空格、token

image
image

  1. 对于 replace 方法, 只有替换成功才会移除重复的空格、token

image

  1. 对于 toggle 切换, 只有修改列表才会移除重复的空格、token

image

三、DOMTokenList 实际用途

  1. 类名管理: DOMTokenList 常常和 classList 强绑定, 在实际开发中, class 属性通常用于定义元素的样式和行为, 而 DOMTokenList 提供了便利的方法来管理这些类名!!!

  2. 操作其他空格分隔的字符串: 从 DOMTokenList 特性出发, 我们可以想象到的一个场景就是通过它来处理一串由空格分隔的字符串, 通过它可以很方便的对子串进行增、删、改、查、替换、遍历等操作!!

四、DOMTokenList 的局限性和注意事项

  1. 不支持重复 token: DOMTokenList 中不支持添加重复的 token
  2. 不能设置分隔符: DOMTokenList 只能处理由空格分隔的字符串, 对于这个分隔符(空格)是没办法修改的

五、参考

  • JavaScript classList
  • DOMTokenList
  • Element classList

image


http://www.ppmy.cn/ops/130458.html

相关文章

SpringBoot整合minio服务

这里我选用的是JDK1.8 SpringBoot2.3.12.RELEASE 一、导入依赖 <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.2</version> </dependency> 二、导入工具类 注意&#xff1a;需要在…

NET Framework的AOP实施方法1 ContextBoundObject

NET Core的AOP实施方法1 DispatchProxy NET Framework的AOP实施方法1 ContextBoundObject NET Framework的AOP实施方法2 RealProxy 源码见Github ContextBoundObject NET Framework需要实现AOP&#xff0c;可以借助于System.Runtime.Remoting.Contexts命名空间中的ContextBo…

动态ip如何自动更换ip

在探讨如何自动更换动态IP地址时&#xff0c;我们首先需要理解动态IP的基本概念。IP地址&#xff0c;即互联网协议地址&#xff0c;分配给每台连接到互联网的设备的唯一标识符。与传统静态IP地址不同&#xff0c;动态IP地址是由网络服务提供商&#xff08;ISP&#xff09;动态分…

linux命令行的艺术

文章目录 前言基础日常使用文件及数据处理系统调试单行脚本冷门但有用仅限 OS X 系统仅限 Windows 系统在 Windows 下获取 Unix 工具实用 Windows 命令行工具Cygwin 技巧 更多资源免责声明 熟练使用命令行是一种常常被忽视&#xff0c;或被认为难以掌握的技能&#xff0c;但实际…

【Unity实战笔记】第二十二 · 基于SMB的角色控制中遇到的一些问题(斜坡移动鬼畜、落地卡顿、角色突进、头发动画失效等)

【Unity实战笔记】第二一 基于状态模式的角色控制——以UnityChan为例【Unity学习笔记】第十一 动画基础&#xff08;Animation、状态机、root motion、bake into pose、blendTree、大量案例&#xff09; 注&#xff1a; 本文紧接上一篇 Unity实战笔记 第二一&#xff0c;补…

硅谷甄选(三)登录注册

今天跑了步很舒服 一.登录模块 1.1登录路由静态组件 src\views\login\index.vue <template><div class"login_container"><el-row><el-col :span"12" :xs"0"></el-col><el-col :span"12" :xs&quo…

【学习】ZLMediaKit试用

服务端准备 下载ZLMediaKit压缩包&#xff0c;解压 /linux/Release路径下启用MediaServer ./MediaServer -d &/linux/Release路径下config.ini更改配置 也可以将进入web控制台 rtmp默认端口1935, rtsp默认端口554,http默认端口80, SSL默认端口443 进入web控制台 http…

js中什么是闭包,它和柯里化函数有什么关系

在JavaScript中&#xff0c;闭包是一个非常重要的概念&#xff0c;它指的是一个函数和它声明时所处的词法环境的组合。这意味着该函数可以访问并操作它被创建时作用域中的变量&#xff0c;即使它在那个作用域之外被调用。 闭包的定义和特点 访问外部变量&#xff1a;闭包允许…