ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

动态用户界面交互实战:用原生 JavaScript 打造可复用的下拉菜单与图片轮播

动态用户界面交互实战:用原生 JavaScript 打造可复用的下拉菜单与图片轮播 动态用户界面交互实战用原生 JavaScript 打造可复用的下拉菜单与图片轮播【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum本文基于 The Odin Project 课程仓库中的《Dynamic User Interface Interactions》一课位于 archive/javascript/javascript_in_the_real_world/dynamic_user_interface_interactions.md系统讲解下拉菜单与图片轮播这两类最常用的前端交互组件的原理与实现。课程原意是不再引入新知识点而是让你把已有的 DOM 操作、事件处理与 CSS 技能组合起来实战。读完本文你将掌握用纯 JavaScript不依赖 Bootstrap 等框架实现可复用的下拉菜单、从零搭建带箭头切换/导航圆点/自动播放的图片轮播并学会用 ES6 模块与 npm 把这类组件打包成可发布的独立库。一、为什么单独开设一节动态交互实战课JavaScript 既能构建运行在任何地方的复杂 Web 应用也常常被用在更小规模的场景里——它是把普通网站粘合在一起的胶水让下拉菜单能展开、让图片轮播能滑动。这门课的价值在于当你已经掌握了 DOM 操作与事件、CSS 布局与动画这些基础能力之后你需要一个专门的机会把它们组合起来形成日常开发中每天都会用到的肌肉记忆。课程在开篇明确了两点本节不引入任何新知识点核心目标是练习你不需要借助 Bootstrap 这类臃肿的框架。课程对 Bootstrap 没有任何意见只是强调一个下拉菜单和一个轮播图用你已学过的技术完全可以手写出来。这正是前端工程师的基本功任何 UI 组件先能徒手实现再谈使用框架。下面的章节将把原课程中的两个实战任务拆解为可运行、可复用的完整方案。二、下拉菜单Drop-down Menu2.1 组成部分与职责划分下拉菜单在各类网站中几乎随处可见——比如点击一个由三个点或三条线组成的图标按钮随即弹出一列选项。它的典型结构只有两个部分一个切换可见性的按钮toggle button负责控制下拉内容显示/隐藏下拉内容本身dropdown content通常是编辑复制删除这类触发具体动作的菜单项或导航栏中跳转到站内其他页面的链接。原课程特别强调了一条职责边界切换按钮只在点击时触发内容的可见性切换菜单项只在点击时触发具体动作执行操作或跳转页面。也就是说按钮管开关菜单项管动作两者不要混为一谈。这个原则保证了组件的语义清晰也便于后面做可访问性无障碍增强——比如让键盘用户用Enter/Space打开菜单、用方向键在菜单项之间移动。2.2 基础实现硬编码 HTML class 切换原课程要求菜单项直接硬编码进 HTML用 JavaScript 控制显示/隐藏。实现方式有两种——给元素添加/移除一个类如visible或者直接在 JS 中操作style。推荐前者类切换与 CSS 解耦样式全部收敛在样式表里且能自然配合 CSS 过渡transitions 做展开动画。!-- dropdown.html -- div classdropdown button classdropdown__toggle typebutton⋮/button ul classdropdown__menu libutton typebutton编辑/button/li libutton typebutton复制/button/li libutton typebutton删除/button/li /ul /div/* dropdown.css */ .dropdown__menu { display: none; /* 也可以结合 transition 与 opacity/transform 做平滑展开 */ } .dropdown__menu.visible { display: block; }// dropdown.js const toggle document.querySelector(.dropdown__toggle); const menu document.querySelector(.dropdown__menu); toggle.addEventListener(click, () { menu.classList.toggle(visible); });这里用到的querySelector、classList.toggle和addEventListener都是 DOM 操作与事件 一课中的核心 API。关于事件绑定原课程在 DOM 事件一课中对比过三种方式值得在这里回顾方式示例缺点HTML 内联属性button onclick...JS 混入 HTML且一个元素只能绑定一个onclickDOM 属性赋值btn.onclick fn同样只能绑定一个处理函数addEventListenerbtn.addEventListener(click, fn)可绑定多个监听器关注点分离推荐2.3 可复用性从一个菜单到任意多个菜单原课程对下拉菜单提出了硬性要求JS 逻辑必须可复用——页面上放多少组下拉菜单都只用同一份逻辑。核心做法是不要对具体元素写死引用而是用querySelectorAll收集所有组件再逐个绑定。下面是一个makeDropdown工厂函数每组.dropdown独立工作// dropdown.js function makeDropdown(dropdown) { const toggle dropdown.querySelector(.dropdown__toggle); const menu dropdown.querySelector(.dropdown__menu); toggle.addEventListener(click, () { menu.classList.toggle(visible); }); // 可选点击菜单外部时收起 document.addEventListener(click, (event) { if (!dropdown.contains(event.target)) { menu.classList.remove(visible); } }); } document.querySelectorAll(.dropdown).forEach(makeDropdown);要点拆解querySelectorAll返回的是 NodeList不是数组。它支持forEach等少数方法但缺少map、filter等数组方法如需完整数组能力可以用Array.from()或展开运算符[...nodeList]转换见 DOM 操作与事件。事件对象event.target指向实际被点击的 DOM 节点。上面的点击外部收起正是利用event.target与dropdown.contains()判断点击是否落在组件之外——这是所有下拉菜单、弹窗组件的通用模式。事件回调中的函数在绑定到事件监听器时即成为callback回调函数这是理解addEventListener用法的关键。2.4 变体hover 触发原课程允许菜单点击或悬停触发任选其一。悬停实现通常依赖mouseenter/mouseleave它们不像mouseover/mouseout那样会在子元素间冒泡更稳定toggle.addEventListener(mouseenter, () menu.classList.add(visible)); dropdown.addEventListener(mouseleave, () menu.classList.remove(visible));实践中往往做成点击 悬停混合模式这里不再展开但原理完全相同。2.5 进阶把组件打包成 npm 模块原课程给出的加分项是如果代码打包成模块可以发布到 npm以后在任何项目里随时安装使用。这一步需要串联课程中已经学过的三块知识ES6 模块ESM用export/import组织代码。模块拥有独立私有作用域只有显式导出的成员才对外可见见 ES6 模块Webpack 打包浏览器不能直接运行散落的模块文件需要打包。先在项目根目录初始化并安装 Webpack详见 Webpacknpm init -y --init-typemodule npm install --save-dev webpack webpack-clinpm 发布把打包产物或模块源码通过npm publish发布之后在任意项目里npm install 你的包名即可复用。在 Webpack 一课中课程还介绍了src源代码与dist构建产物的目录约定工作都在src内完成构建输出到dist部署只上传dist。遵循这一约定你的下拉菜单组件就能变成一个开发一次、处处复用的标准 npm 包。三、图片轮播Image Carousel3.1 结构原理画框 长条底片图片轮播在电商、新闻等网站极其常见适合做广告展示、用有限的屏幕空间呈现多张内容。原课程给出了它的经典结构模型一个充当相框picture frame的div在它后面是另一个宽得多的div里面装着轮播的所有图片。这条图片底片在相框后面水平移动相框窗口露出底片的哪一段就显示哪一张图。其余所有控件箭头、圆点叠加在整个结构之上。把它翻译成 DOM 就是三层嵌套!-- carousel.html -- div classcarousel !-- 外层承载箭头、圆点 -- div classcarousel__frame !-- 相框overflow hidden决定窗口大小 -- div classcarousel__track !-- 底片display flex宽度图片数×100% -- img srcslide-1.jpg alt第一张幻灯片 img srcslide-2.jpg alt第二张幻灯片 img srcslide-3.jpg alt第三张幻灯片 /div /div button classcarousel__arrow carousel__arrow--prev‹/button button classcarousel__arrow carousel__arrow--next›/button div classcarousel__dots/div /div/* carousel.css */ .carousel__frame { width: 600px; /* 相框宽度 单张幻灯片宽度 */ overflow: hidden; /* 关键把窗口之外的幻灯片裁掉 */ } .carousel__track { display: flex; width: 300%; /* 3 张图 300%n 张图即 n×100% */ transition: transform 0.3s ease; /* 可选让切换平滑 */ } .carousel__track img { width: 600px; /* 与相框同宽保证每张图恰好占满一屏 */ flex-shrink: 0; }3.2 核心状态与定位一个数字决定一切轮播的整个状态可以压缩为一个变量当前索引currentIndex0 到slides.length - 1。底片通过transform: translateX(-currentIndex × 100%)平移就能让第currentIndex张图对准相框窗口。原课程明确说过渡不必平滑、不必动画先保证切换到正确的幻灯片。这意味着第一步可以用最简单的方式实现动画属于后续的锦上添花见下文 3.6。3.3 上一张 / 下一张函数与箭头按钮原课程要求先构建next/previous两个函数再用左右箭头按钮触发// carousel.js const track document.querySelector(.carousel__track); const slides [...track.children]; // NodeList - 数组 const frameWidth track.querySelector(img).getBoundingClientRect().width; let currentIndex 0; function updateSlide() { track.style.transform translateX(-${currentIndex * 100}%); } function next() { currentIndex (currentIndex 1) % slides.length; // 到达末尾回到第一张 updateSlide(); } function previous() { currentIndex (currentIndex - 1 slides.length) % slides.length; updateSlide(); } document.querySelector(.carousel__arrow--next).addEventListener(click, next); document.querySelector(.carousel__arrow--prev).addEventListener(click, previous);两个细节值得注意%取模运算实现循环(i 1) % n让索引在 0..n-1 间循环这就是到头自动回绕的逻辑translateX(-currentIndex * 100%)用百分比而非像素百分比相对底片自身宽度计算而底片宽度恰好是图片数 × 相框宽因此-100%正好移动一张图的距离天然适配任意相框尺寸。3.4 导航圆点动态生成 当前态高亮原课程要求在轮播下方用 CSS 画一排空心圆每个圆代表一张幻灯片当前幻灯片对应的圆被填充点击任意圆可直接跳到对应幻灯片。动态生成比手写 N 个圆点更符合可复用精神——幻灯片数量变了圆点自动跟着变// carousel.js const dotsContainer document.querySelector(.carousel__dots); slides.forEach((_, index) { const dot document.createElement(button); dot.classList.add(carousel__dot); dot.addEventListener(click, () { currentIndex index; updateSlide(); updateDots(); }); dotsContainer.appendChild(dot); }); const dots [...dotsContainer.children]; function updateDots() { dots.forEach((dot, index) { dot.classList.toggle(active, index currentIndex); }); }/* carousel.css */ .carousel__dot { width: 12px; height: 12px; border-radius: 50%; border: 2px solid #333; background: transparent; /* 空心圆未激活 */ } .carousel__dot.active { background: #333; /* 实心圆当前幻灯片 */ }这里用到的document.createElement、appendChild、classList.toggle带第二个布尔参数都是 DOM 操作与事件 中的标准 API。3.5 5 秒自动播放setInterval原课程要求轮播每 5 秒自动前进一张使用定时器即可// carousel.js setInterval(next, 5000);进一步可以把定时器封装成可启停的 API并让手动操作后重启计时这是真实轮播的常见交互属于课程范围之外的合理延伸但实现只用到已学知识let autoPlay setInterval(next, 5000); function restartTimer() { clearInterval(autoPlay); autoPlay setInterval(next, 5000); } // 手动切换后调用 restartTimer()3.6 平滑过渡可选增强原课程明确过渡不必平滑但如果你想让观感更好只需要两行改动把 CSS 过渡 中的知识用上——给底片加一条transition位置切换就自动变成滑动动画.carousel__track { transition: transform 0.3s ease; }课程在 CSS 过渡 一课中指出除伪类如:hover之外JavaScript 添加/移除类同样能触发过渡。轮播正是JS 改变transform、CSS 负责平滑这一分工的典型例子。若想更进一步做淡入淡出等效果可参考 keyframes 动画。3.7 完整任务清单对照原课程原课程要求实现位置左右各一个箭头前进/后退next()/previous() 箭头按钮监听每 5 秒自动前进setInterval(next, 5000)底部导航圆点指示当前幻灯片动态生成button圆点 .active类圆点可点击直达对应幻灯片圆点click监听中设置currentIndex宽div装幻灯片容器作相框.carousel__trackflex 宽度 n×100%嵌套在.carousel__frameoverflow hidden内图片尺寸不必过分纠结相框与图片宽度统一即可重点是轮转逻辑四、贯穿全程的工程化建议原课程虽然聚焦于两个组件的实现但其练习要求天然串联起了课程体系中的几条主线DOM 与事件是地基querySelector选择节点、classList切换类、addEventListener绑定回调、event.target判定点击目标全部来自 DOM 操作与事件模块化让代码可复用把makeDropdown、轮播逻辑封装成模块并用export导出是 ES6 模块 一课的实践打包与发布用 Webpack 将模块打包配合 npm scripts如npm run build固化构建命令见 revisiting_webpack即可把组件发布成 npm 包代码整洁写组件时注意函数职责单一、命名清晰遵循 clean code 的原则。五、知识检查对照原课程的三个知识检查问题检验你的掌握程度下拉菜单由哪两个主要部分组成——一个负责切换可见性的按钮以及承载动作/链接项的下拉内容本身。什么场景适合使用下拉菜单——需要在不占用页面空间的前提下收纳一组操作编辑、复制、删除等或导航链接时例如导航栏、列表行操作、设置菜单。使用图片轮播有什么好处——适合广告与商品展示、用有限的屏幕空间呈现多张图片、支持自动播放/手动切换/跳转到指定幻灯片等多种交互方式且完全可以用已掌握的 HTML/CSS/JS 手写实现。六、小结本课不教新语法而是把已经学过的 DOM 操作、事件处理、CSS 布局与动画重新组合成两个真实可用的组件下拉菜单 按钮管开关 内容管动作用classList.toggle控制可见性用querySelectorAll forEach实现多实例复用图片轮播 相框overflow: hidden 底片flex 宽条用currentIndex一个变量驱动translateX定位配以next/previous取模循环、动态导航圆点与setInterval自动播放。它们不需要 Bootstrap不需要任何框架——这正是 The Odin Project 在 dynamic_user_interface_interactions.md 一课中想让你建立的信心。把这两个组件写熟再配合 ES6 模块与 Webpack 打包发布你手里的原生 JavaScript 就已经具备应对日常开发中绝大多数 UI 交互场景的能力。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表