data-category是绑定标签云与筛选逻辑的唯一可靠纽带,必须统一用于按钮、内容块等所有可筛选项,值小写无空格无符号;点击用e.target.closest('[data-category]')获取源,筛选时先设所有元素display=none防闪动,再用querySelectorAll匹配并设display=block;多选用Set管理状态,避免classList操作引发重排;语义上用<ul class="tag-cloud">和<button>容器保障无障碍与SEO;URL hash同步筛选状态需手动解析拼接,防止界面与地址栏不一致。

data-category 是绑定标签云与筛选逻辑的唯一可靠纽带,别用 class 模拟分类,也别靠 id 匹配——前者易冲突,后者强制唯一,两者都会在多维度或重复分类时崩掉。
怎么让标签云点击后精准筛选内容
核心是统一用 data-category(或你自定义的 data-*)标记所有可筛选项:按钮、内容块、甚至子项。值必须小写、无空格、无符号,比如 data-category="react",而不是 data-category="React.js" 或 data-category="react js"。
点击事件监听必须用 e.target.closest('[data-category]') 获取触发源,否则点到图标、文字或内嵌 <span> 时,e.target.dataset.category 会是 undefined。
筛选动作分两步走:
立即学习“前端免费学习笔记(深入)”;
- 默认所有待筛选元素设
style.display = "none"(CSS 或 JS 初始化阶段统一处理,防首屏闪动) - 点击后,先
document.querySelectorAll('[data-category="xxx"]')拿匹配节点,再逐个设node.style.display = "block"
多选标签组怎么避免 class 冲突和状态混乱
多选不是靠加一堆 class="active js selected" 来维护状态,而是用 Set 存已选值:
- 每次点击,用
selected.has(item.dataset.category)判断是否该显示 - 支持 Ctrl/Cmd 多选时,
e.ctrlKey或e.metaKey判断修饰键,再增删Set中的值 - 清空筛选时,直接
selected.clear(),比遍历 DOM 移 class 快且干净
千万别在循环里反复读写 classList.toggle() 或 style.display —— 这会触发多次重排,列表一过百条就明显卡顿。
为什么用 <ul class="tag-cloud"> 而不是 <div> 堆标签
语义上,标签云是一组关键词集合,<ul> 天然表达“无序列表”关系;对屏幕阅读器、SEO、CSS 选择器都更友好。用 <div> 模拟,等于主动丢掉结构信号。
JS 动态渲染时,搜索引擎可能延迟识别或完全忽略关键词层级;CSS 里想给第 3 个标签加边框?ul.tag-cloud li:nth-child(3) 直接可用,div > span:nth-child(3) 却可能被中间插入的文本节点打断。
另外,<button> 必须作为每个标签的容器,而非仅包裹文字——它提供键盘聚焦、aria-pressed 支持、原生 focus 管理,比 <div role="button"> 少一半无障碍补丁工作。
筛选状态怎么同步到 URL hash 而不干扰 history
用 window.location.hash 存已选值最轻量,比如 #category=react&category=vue&status=active。解析时别依赖 URLSearchParams(IE 不支持),改用正则或手动切分:
- 写入:拼接字符串后赋值
window.location.hash = hashString,不调pushState - 读取:监听
hashchange事件,用location.hash.slice(1).split('&').map(...)提取键值对 - 注意重复参数:多个
category=xxx要合并进一个Set,别误当单值覆盖
最容易被忽略的是:hash 变化不会触发页面重载,但若你用 history.pushState 手动干预,又没同步更新 UI 状态,用户点浏览器后退就会看到界面和 URL 不一致——这种错位比没同步还难排查。



















