不使用JavaScript如何实现元素的显示与隐藏?
我在开发应用时,最初通过DOMTokenList的add()、remove()方法切换类名,控制元素显示隐藏。随着功能叠加,这类重复代码越来越多,初始写法的示例如下:
button.addEventListener("click", () => { elem1.classList.add("display-none"); elem2.classList.remove("display-none"); elem3.classList.remove("display-none"); elem4.classList.add("display-none"); }); button2.addEventListener("click", () => { elem1.classList.remove("display-none"); elem2.classList.add("display-none"); elem3.classList.add("display-none"); elem4.classList.remove("display-none"); });
我一共有7段逻辑和上述示例高度相似的代码,因此开始探索更简洁的实现方案,首先尝试了纯CSS写法,代码如下:
.box { --displayRed: block; --displayGreen: none; --displayBlue: none; height: 100px; width: 100px; } .box--red { display: var(--displayRed); background-color: #ff0000; } .box--green { display: var(--displayGreen); background-color: #00ff00; } .box--blue { display: var(--displayBlue); background-color: #0000ff; } .box--red:target { --displayRed: block; --displayGreen: none; --displayBlue: none; } .box--green:target { --displayRed: none; --displayGreen: block; --displayBlue: none; } .box--blue:target { --displayRed: none; --displayGreen: none; --displayBlue: block; }
<div> <div class="box"> <div id="boxRed" class="box box--red"></div> <div id="boxGreen" class="box box--green"></div> <div id="boxBlue" class="box box--blue"></div> </div> <nav> <ul> <li><a href="#boxRed">显示红色方块</a></li> <li><a href="#boxGreen">显示绿色方块</a></li> <li><a href="#boxBlue">显示蓝色方块</a></li> </ul> </nav> </div>
我原本预期点击对应颜色方块的跳转链接时,当前显示的方块会自动隐藏,仅展示链接对应颜色的方块。但实际测试时,点击链接只会触发页面滚动,原本显示的红色方块不会自动隐藏。
我查阅了CSS伪类、选择器的官方文档,找了相关教程,也参考了社区里纯CSS实现元素显隐的相关问答,始终没找到可行的实现方案,欢迎提供有效的实现思路。
你的纯CSS:target方案不生效的核心原因是CSS变量存在作用域限制:在.box--red:target选择器下修改的CSS变量,只会作用在被锚点命中的红色方块自身和它的子元素,无法影响同级的绿色、蓝色方块,因此其他方块的display属性始终取初始值,不会自动隐藏。
下面提供两类可直接落地的实现方案,按需选择即可:
方案1:纯CSS实现(无JavaScript)
(1):target 简化版(适配现代浏览器)
不需要借助CSS变量,直接通过:target伪类匹配当前命中的方块控制显隐,配合:has()伪类实现默认展示逻辑,代码量极小:
.box { height: 100px; width: 100px; /* 默认所有方块隐藏 */ display: none; } .box--red { background-color: #ff0000; } .box--green { background-color: #00ff00; } .box--blue { background-color: #0000ff; } /* 锚点命中的方块显示 */ .box:target { display: block; } /* 无任何锚点命中时,默认显示红色方块 */ .box-container:not(:has(:target)) .box--red { display: block; }
对应HTML只需要给方块的父容器加一个box-container类即可,原有导航链接不需要修改。
(2)单选框方案(兼容老旧浏览器)
如果需要兼容不支持:has()的浏览器,可以用单选框+<label>的经典纯CSS Tab实现,兼容性覆盖到IE9及以上:
/* 隐藏原生单选框 */ .color-tab { position: absolute; opacity: 0; pointer-events: none; } .box { height: 100px; width: 100px; display: none; } .box--red { background-color: #ff0000; } .box--green { background-color: #00ff00; } .box--blue { background-color: #0000ff; } /* 单选框选中时,对应颜色的方块显示 */ #tabRed:checked ~ .box-container .box--red, #tabGreen:checked ~ .box-container .box--green, #tabBlue:checked ~ .box-container .box--blue { display: block; }
对应HTML调整如下:
<div> <!-- 单选框组,默认选中红色 --> <input type="radio" name="colorTab" id="tabRed" class="color-tab" checked> <input type="radio" name="colorTab" id="tabGreen" class="color-tab"> <input type="radio" name="colorTab" id="tabBlue" class="color-tab"> <div class="box-container"> <div class="box box--red"></div> <div class="box box--green"></div> <div class="box box--blue"></div> </div> <nav> <ul> <li><label for="tabRed">显示红色方块</label></li> <li><label for="tabGreen">显示绿色方块</label></li> <li><label for="tabBlue">显示蓝色方块</label></li> </ul> </nav> </div>
方案2:极简JavaScript实现(适配多组切换场景)
你之前的JS代码冗余是因为逐元素、逐按钮写了重复的类名切换逻辑,只要做一层统一封装,不管有多少组显隐切换,核心JS代码只需要写一次:
- 给所有触发按钮加
data-target属性,标记要显示的分组名 - 给所有需要切换显隐的元素加
data-group属性,标记所属分组
示例代码:
// 统一绑定所有切换按钮的事件,不需要逐个写监听 document.querySelectorAll('[data-toggle-target]').forEach(trigger => { trigger.addEventListener('click', () => { const currentGroup = trigger.dataset.toggleTarget; // 遍历所有待切换元素,属于当前分组的显示,否则隐藏 document.querySelectorAll('[data-toggle-group]').forEach(elem => { elem.classList.toggle('display-none', elem.dataset.toggleGroup !== currentGroup); }) }) })
后续新增切换分组时,只需要给对应按钮和元素加数据属性即可,不需要修改JS逻辑,比你原来逐行写add/remove的维护成本低很多。
内容的提问来源于stack exchange,提问作者MART3

