JavaScript实现flex布局点击盒子调整自身及其他元素宽度
实现方案
核心思路
不用写复杂的JS逻辑判断,优先用CSS处理视觉状态,JS只负责维护选中状态锁,性能更好代码也更易维护:
- 初始状态、hover状态的宽度变化优先用CSS实现,通过父容器的状态类区分「无选中项」「有选中项」两种场景,避免hover效果干扰点击后的选中态
- JS只处理点击事件:每次点击先清空所有盒子的选中标记,再给当前点击的盒子加上选中类,同时给父容器加状态标记锁定hover
- 预留重置方法,后续加关闭按钮直接调用即可
完整代码
CSS部分
/* 父容器基础样式 */ section { display: flex; width: 100%; height: 300px; gap: 4px; /* 盒子间距,不需要可删除 */ } /* 盒子基础样式 */ .box { width: 25%; /* 初始宽度 */ transition: width 0.3s ease; /* 宽度变化加过渡动画,效果更丝滑,不需要可删除 */ cursor: pointer; /* 原有盒子自定义样式比如背景色、圆角等可直接保留 */ } /* 无选中项时,hover当前盒子宽度 */ section:not(.has-selected) .box:hover { width: 40%; } /* 无选中项时,hover某个盒子,其余盒子宽度变为20% */ section:not(.has-selected) .box:hover ~ .box, section:not(.has-selected):has(.box:hover) .box:not(:hover) { width: 20%; } /* 选中态盒子宽度 */ .box.selected { width: 85%; } /* 有选中项时,其余非选中盒子宽度 */ section.has-selected .box:not(.selected) { width: 5%; }
JS部分
// 获取页面元素 const boxContainer = document.querySelector('section'); const boxes = document.querySelectorAll('.box'); // 给每个盒子绑定点击事件 boxes.forEach(box => { box.addEventListener('click', () => { // 先清除所有盒子的选中状态 boxes.forEach(item => item.classList.remove('selected')); // 给当前点击的盒子添加选中类 box.classList.add('selected'); // 给父容器加选中标记,禁用hover效果 boxContainer.classList.add('has-selected'); }) }) // 预留重置方法,后续给关闭按钮绑定即可 function resetBoxWidth() { boxes.forEach(item => item.classList.remove('selected')); boxContainer.classList.remove('has-selected'); } // 后续开发关闭功能时,给按钮绑定上述方法即可,示例: // document.querySelector('.close-btn').addEventListener('click', resetBoxWidth)
兼容说明
上面的CSS用到了:has()选择器,2023年之后发布的主流浏览器(Chrome 105+、Firefox 121+、Safari 15.4+)都已经原生支持,如果需要兼容更老的浏览器,可以把hover效果改用JS实现,把下面这段代码追加到JS文件里即可:
// 旧浏览器兼容:不支持:has()时用JS实现hover效果 if (!CSS.supports('selector(:has(*))')) { boxes.forEach(box => { box.addEventListener('mouseenter', () => { // 有选中项时不触发hover宽度变化 if (boxContainer.classList.contains('has-selected')) return; boxes.forEach(item => item.style.width = '20%'); box.style.width = '40%'; }) box.addEventListener('mouseleave', () => { if (boxContainer.classList.contains('has-selected')) return; boxes.forEach(item => item.style.width = '25%'); }) }) }
内容的提问来源于stack exchange,提问作者Mika
相关产品推荐
相关产品推荐

