在React中如何实现两个列表项的selected类名互斥切换
无序列表单选选中排他效果实现方案
这个需求是典型的同组选项单选逻辑,核心要实现的就是「选中新项时自动清除其他项的旧选中状态」,不需要依赖任何第三方库,用原生JS就能完成,还能同步更新你代码里预留的aria-selected可访问属性,适配屏幕阅读器的识别逻辑。
核心实现思路
- 监听列表项的点击事件
- 触发点击时,先清空同组内所有元素的
selected类名和对应的选中属性 - 单独给当前被点击的列表项添加
selected类名和对应的选中属性
注意点:不建议直接用
item.className = 'selected'的方式赋值,这种写法会完全覆盖元素上原有的所有类名,优先使用classList系列方法操作类名,不会误伤其他已有样式类。
基础版完整实现
这个版本适合列表项数量固定、后续不会动态增减的场景,直接给每个li绑定点击事件即可:
<style> /* 自定义selected类的展示样式,方便直观看到效果 */ li.selected { color: #1677ff; font-weight: 600; } </style> <ul> <li role="option" aria-selected="false"> yes </li> <li role="option" aria-selected="false"> no </li> </ul> <script> // 获取所有带option角色的li元素 const allOptions = document.querySelectorAll('ul li[role="option"]') allOptions.forEach(option => { option.addEventListener('click', function() { // 遍历清除所有选项的选中状态 allOptions.forEach(item => { item.classList.remove('selected') item.setAttribute('aria-selected', 'false') }) // 给当前点击的选项设置选中状态 this.classList.add('selected') this.setAttribute('aria-selected', 'true') }) }) </script>
优化版(事件委托实现)
如果你的列表项后续会通过接口动态加载、动态增删,给每个li单独绑定事件会有不必要的性能损耗,这时候可以把事件绑定在父级ul上,利用事件冒泡机制统一处理点击逻辑,后续新增的li元素不需要重新绑定事件就能自动适配交互:
const listContainer = document.querySelector('ul') listContainer.addEventListener('click', function(e) { // 判断当前点击的元素是不是选项li const targetOption = e.target.closest('li[role="option"]') if (!targetOption) return // 清除当前组内所有旧的选中状态 this.querySelectorAll('li.selected').forEach(item => { item.classList.remove('selected') item.setAttribute('aria-selected', 'false') }) // 给当前点击的选项设置选中 targetOption.classList.add('selected') targetOption.setAttribute('aria-selected', 'true') })
内容的提问来源于stack exchange,提问作者Angie
相关产品推荐
相关产品推荐

