ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

原生JS三屏交互组件:一键收放与自动轮播实现

原生JS三屏交互组件:一键收放与自动轮播实现 简介这份资源面向前端开发者与交互设计学习者聚焦「三屏效果 一键关闭、一键展开」这一常见界面交互模式适用于会议展示、产品介绍、数据可视化等需要分屏呈现信息的场景。包内共10个文件以6个html页面、2个js脚本、1个css样式表和1份docx说明文档为主压缩包约338KB结构轻量便于直接运行与二次修改。内容围绕HTML结构搭建、CSS响应式布局与过渡动画、JavaScript控制显隐与自动弹开逻辑展开并涉及焦点管理、无障碍访问及requestAnimationFrame性能优化等细节docx文档则补充了开发与设置说明。目前已有532人学习适合希望快速掌握分屏交互实现思路、对照源码理解完整逻辑的前端学习者参考。1. 三屏交互的真实需求从“堆三块 div”到一键收放很多前端开发者第一次接到“三屏效果”需求时脑子里蹦出来的方案就是横向排三个div加个overflow-x: auto就交差。但真正落地到会议展示、产品介绍页或者数据可视化大屏时问题立刻暴露用户想聚焦看某一屏时另外两屏占着横向空间想对比三屏数据时又得来回滚动。这个三屏.zip资源包里的threedemo目录给出的解法是“一键关闭、一键展开”加自动弹开——默认只露第一屏点击展开后三屏并排再点关闭收回同时支持定时轮播切换。它适合正在做前端页面大屏布局、需要快速复现一套可交互多屏结构的开发者尤其是手头有index.html、style.css、threedemo.js这套原生三件套、不想引入重型框架的场景。压缩包里还附了一份三屏开发与设置说明20211219.docx说明作者在交付时已经把配置项和调用方式整理过一轮不是扔一堆源码就完事。2. 拆开 threedemoHTML 骨架、CSS 状态机与 JS 定时器怎么配合2.1 三屏的 DOM 结构不是随便套三层 div打开index.html核心结构是三个并列的section每个section带一个screen类和一个独立的id外层包一个#three-screen-wrap作为定位和尺寸的锚点。这种写法的好处是CSS 可以直接用#three-screen-wrap .screen控制所有屏的公共样式用#screen-1、#screen-2、#screen-3做差异化处理。常见做法是给每个section内部再分两层一层放标题或缩略图一层放详细内容这样关闭状态下只显示标题层展开后详细内容才参与布局。!-- index.html 核心结构节选 -- div idthree-screen-wrap classis-collapsed section idscreen-1 classscreen div classscreen-head第一屏标题/div div classscreen-body第一屏详细内容/div /section section idscreen-2 classscreen div classscreen-head第二屏标题/div div classscreen-body第二屏详细内容/div /section section idscreen-3 classscreen div classscreen-head第三屏标题/div div classscreen-body第三屏详细内容/div /section button idtoggle-btn typebutton展开/button /div这里的关键参数是外层容器的is-collapsed类。它不控制单个屏的display而是控制整个包裹层的布局模式。展开时移除这个类三屏按flex或grid并排关闭时加上这个类只有#screen-1保持可见其余两屏通过transform: translateX或width: 0收起来。我一般会把is-collapsed作为唯一的状态开关避免在 JS 里同时操作多个屏的style.display那样后期加动画会非常痛苦。2.2 CSS 过渡与初始状态别让第一屏在加载时闪一下style.css里最值得抄的是初始状态的处理。很多实现直接写.screen { display: none; }然后 JS 加载后再显示第一屏结果页面会闪一下白。threedemo 的做法是在 CSS 里就把#screen-1设为opacity: 1; visibility: visible;其余两屏设为opacity: 0; visibility: hidden;同时给#three-screen-wrap加上transition: all 0.4s ease;。这样即使 JS 还没执行第一屏也是正常显示的不会出现内容跳动。/* style.css 状态与过渡节选 */ #three-screen-wrap { display: flex; gap: 16px; transition: all 0.4s ease; } #three-screen-wrap.is-collapsed .screen:not(#screen-1) { opacity: 0; visibility: hidden; width: 0; padding: 0; margin: 0; overflow: hidden; } #three-screen-wrap:not(.is-collapsed) .screen { opacity: 1; visibility: visible; flex: 1; } .screen { transition: opacity 0.3s ease, width 0.4s ease; }参数说明transition的0.4s是展开/关闭的动画时长太短会显得生硬太长会让用户觉得卡。gap: 16px是三屏之间的间距如果要做响应式可以在媒体查询里把flex-direction改成column同时把gap调小。注意width: 0和padding: 0必须同时写否则收起时仍会占位。overflow: hidden是为了防止内容在宽度收缩时溢出。2.3 JS 交互逻辑一键切换、自动弹开与定时器清理threedemo.js的核心只有三个函数toggleScreens()、startAutoPlay()、stopAutoPlay()。一键关闭/展开靠的是切换is-collapsed类自动弹开靠的是setInterval轮换当前激活的屏。这里有一个容易翻车的点自动轮播和手动展开会互相干扰。threedemo 的处理是用户点击展开或关闭按钮时先stopAutoPlay()再执行切换如果当前是展开状态且用户没有手动关闭则重新startAutoPlay()。// threedemo.js 交互逻辑节选 const wrap document.getElementById(three-screen-wrap); const toggleBtn document.getElementById(toggle-btn); let autoTimer null; let currentIndex 0; function toggleScreens() { stopAutoPlay(); const isCollapsed wrap.classList.toggle(is-collapsed); toggleBtn.textContent isCollapsed ? 展开 : 关闭; if (!isCollapsed) { startAutoPlay(); } } function startAutoPlay() { stopAutoPlay(); autoTimer setInterval(() { currentIndex (currentIndex 1) % 3; // 这里可以加高亮当前屏的逻辑比如切换 active 类 document.querySelectorAll(.screen).forEach((el, i) { el.classList.toggle(is-active, i currentIndex); }); }, 3000); } function stopAutoPlay() { if (autoTimer) { clearInterval(autoTimer); autoTimer null; } } toggleBtn.addEventListener(click, toggleScreens);逻辑说明toggleScreens先停掉定时器避免切换过程中自动轮播还在跑。classList.toggle返回布尔值直接用来判断当前是展开还是关闭比手动读className更稳。startAutoPlay里的3000是轮播间隔单位毫秒可以根据内容多少调整。stopAutoPlay里必须把autoTimer置为null否则下次startAutoPlay时clearInterval会拿到一个已经失效的 ID虽然不报错但逻辑上不干净。注意is-active类在 CSS 里可以配合box-shadow或border做当前屏高亮threedemo 的说明文档里提到过这个扩展点。3. 避坑与排查三屏效果从能跑到好用的五个坎3.1 展开后三屏宽度不均第三屏被挤扁现象点击展开后前两屏正常第三屏宽度明显小于其他两屏内容换行严重。原因flex: 1默认是flex: 1 1 0%但如果某个屏内部有固定宽度的元素比如一张width: 600px的图片它会撑开自身导致其他屏分到的空间变小。解决给.screen加上min-width: 0强制 flex 子项可以收缩到内容以下同时把内部图片改成max-width: 100%。3.2 自动轮播在用户点击关闭后仍在后台跑现象用户点了关闭三屏收起了但过几秒又自动展开或者高亮跳变。原因stopAutoPlay只在toggleScreens里调了一次但如果在其他地方比如窗口 resize也触发了startAutoPlay定时器会被重新创建。解决把autoTimer挂到模块级变量每次startAutoPlay前先执行stopAutoPlay并且只在展开状态下才允许启动。threedemo 的源码里就是这么写的但如果你自己改代码很容易漏掉 resize 监听里的清理。3.3 移动端上三屏并排导致横向滚动条现象在手机浏览器打开三屏展开后页面出现横向滚动条用户需要左右拖拽才能看全。原因flex布局在窄屏下仍然保持横向排列总宽度超过视口。解决在媒体查询里把#three-screen-wrap的flex-direction改成column同时把is-collapsed状态下的隐藏逻辑改成max-height: 0而不是width: 0。这样关闭时只露第一屏展开时三屏纵向堆叠符合移动端浏览习惯。3.4 过渡动画过程中点击按钮导致状态错乱现象快速连点展开/关闭按钮三屏会卡在中间状态或者按钮文字和实际状态对不上。原因CSStransition还在执行时JS 已经切换了类名浏览器需要重新计算布局如果此时再切换一次动画会叠加。解决在toggleScreens开头加一个isAnimating标志位动画期间忽略点击或者用wrap.addEventListener(transitionend, ...)在动画结束后再允许下一次操作。threedemo 的说明文档里建议用debounce但我更倾向于用标志位因为transitionend在多个属性过渡时会触发多次。3.5 无障碍访问缺失键盘用户无法操作现象用 Tab 键可以聚焦到按钮但展开后无法通过键盘在三屏之间切换焦点屏幕阅读器也读不出当前哪一屏是激活的。原因section没有加tabindex和aria-hidden按钮没有aria-expanded。解决给每个section加tabindex0在is-collapsed状态下给非第一屏加aria-hiddentrue按钮上加aria-expandedtrue/false并在 JS 里同步更新。这些属性不会影响视觉但能让辅助技术正确识别状态。4. 进阶技巧把三屏效果封装成可配置组件如果你不想每次做新页面都复制一遍threedemo的代码可以把它封装成一个接受配置项的构造函数。下面这个ThreeScreen类是我在 threedemo 基础上改的支持自定义轮播间隔、初始展开状态和切换回调。// 可配置的三屏组件封装 class ThreeScreen { constructor(options {}) { this.wrap document.querySelector(options.wrap || #three-screen-wrap); this.toggleBtn document.querySelector(options.toggleBtn || #toggle-btn); this.interval options.interval || 3000; this.startCollapsed options.startCollapsed ! false; this.onChange options.onChange || function() {}; this.autoTimer null; this.currentIndex 0; this.init(); } init() { if (this.startCollapsed) { this.wrap.classList.add(is-collapsed); this.toggleBtn.textContent 展开; } else { this.wrap.classList.remove(is-collapsed); this.toggleBtn.textContent 关闭; this.startAutoPlay(); } this.toggleBtn.addEventListener(click, () this.toggle()); } toggle() { this.stopAutoPlay(); const isCollapsed this.wrap.classList.toggle(is-collapsed); this.toggleBtn.textContent isCollapsed ? 展开 : 关闭; this.toggleBtn.setAttribute(aria-expanded, String(!isCollapsed)); if (!isCollapsed) { this.startAutoPlay(); } this.onChange(isCollapsed); } startAutoPlay() { this.stopAutoPlay(); this.autoTimer setInterval(() { this.currentIndex (this.currentIndex 1) % 3; this.wrap.querySelectorAll(.screen).forEach((el, i) { el.classList.toggle(is-active, i this.currentIndex); }); }, this.interval); } stopAutoPlay() { if (this.autoTimer) { clearInterval(this.autoTimer); this.autoTimer null; } } } // 调用示例 new ThreeScreen({ interval: 5000, startCollapsed: true, onChange: (collapsed) { console.log(当前状态, collapsed ? 已关闭 : 已展开); } });参数说明wrap和toggleBtn是选择器字符串方便在多个页面复用。interval控制轮播速度默认 3000 毫秒。startCollapsed决定初始是收起还是展开默认收起。onChange是状态切换后的回调可以用来埋点或者联动其他 UI。这个封装没有依赖任何框架直接放在threedemo.js后面就能用。如果你项目里用的是 Vue 或 React把classList.toggle换成响应式状态即可逻辑完全一样。验证方法打开index.html先确认初始只显示第一屏点击展开后三屏并排且间距均匀等待 5 秒看是否自动高亮切换再点击关闭确认收起且轮播停止。用手机浏览器打开检查是否变成纵向堆叠且没有横向滚动条。最后用 Tab 键走一遍确认按钮和每个屏都能聚焦。从那以后我每次做多屏交互都会先把状态类名和定时器清理逻辑写死再动 CSS 动画。这个三屏.zip里的threedemo虽然是个小 demo但把一键关闭、一键展开和自动弹开这三件事的边界处理得比较清楚适合拿来当起点改。希望帮到你。本文还有配套的精品资源点击获取
返回列表