Web-Dev-For-Beginners 之 Terrarium 拖拽项目:用 HTML、CSS 与 DOM 闭包构建交互式玻璃罐植物园并部署上线
【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners
导读
Terrarium(玻璃罐植物园)是 Web-Dev-For-Beginners 课程中第三大模块的完整落地产物:一个用少量 HTML、JavaScript 与 CSS 就能完成的"拖拽式代码冥想"小应用。本文以项目 solution 说明文档 为核心骨架,结合 solution 目录 下的真实源码(index.html、style.css、script.js),完整讲解从页面结构搭建、罐子与植物的 CSS 绘制,到基于 Pointer Events 与 JavaScript 闭包的拖拽系统实现,最后演示如何借助 Azure Static Web Apps 一键把项目发布到公网。读完后,你将掌握 DOM 操作、闭包状态管理、事件生命周期以及静态站点部署的完整实战链路。
一、项目概览:什么是 Terrarium
按照 solution README 的描述,Terrarium 是一个 "small drag and drop code-meditation"——一次通过拖拽完成的小型代码冥想。它的技术构成非常克制:
- HTML:搭建页面的基础骨架(导航、植物选择区、玻璃罐结构);
- CSS:绘制并美化整个界面,包括玻璃罐的透明质感与页面布局;
- JavaScript:为 14 株植物注入拖拽交互,让用户可以把植物从两侧的"库存区"任意拖入罐中布置。
整个项目使用纯原生(vanilla)技术栈,不依赖任何框架,是 DOM 与闭包课程 的最终配套解决方案。页面加载后,用户按住任意一株植物即可拖动,松开后植物停留在新位置——这正是很多现代交互(看板拖拽、文件上传、相册排序)背后的基础原理。
背景说明:玻璃罐的 CSS 造型灵感来自 Jakub Mandra 在 Codepen 上发布的玻璃罐作品,植物插画由课程作者 Jen Looper 使用 Procreate 手绘完成(见 solution README 的 Credits 部分)。本模块对应的教学路径可参考 Terrarium 课程主页 及其三节子课程(HTML 入门、CSS 入门、DOM 与闭包)。
二、工程结构:solution 目录解剖
项目解决方案位于3-terrarium/solution/,结构非常清晰,是一个典型的三件套静态站点:
3-terrarium/solution/ ├── README.md # 项目说明与部署指南 ├── index.html # 页面结构(唯一入口) ├── style.css # 全部样式(布局 + 玻璃罐绘制) ├── script.js # 拖拽交互逻辑(闭包 + Pointer Events) └── images/ ├── plant1.png ~ plant14.png # 14 株手绘植物(400x400 PNG)三个文件各司其职,没有任何构建步骤,用浏览器直接打开 index.html 即可运行。这种"零依赖、零构建"的特性,也是它能被 Azure Static Web Apps 一键托管的根本原因。
三、从源码看实现:三件套如何协同工作
3.1 HTML 骨架:结构决定一切
<index.html> 承担了全部结构定义,页面主体分为三块:
- 导航栏(
<nav>):使用 Font Awesome 图标(通过 index.html 中的 CDN 引入font-awesome/6.4.2)渲染 Home、Plants、Care Tips、About、Contact 五个入口; - 植物选择区(
#plant-selection):左右两个容器#left-container与#right-container,各放置 7 个.plant-holder,每个 holder 内是一张带唯一 ID 的植物图片,共 14 株:
<div class="plant-holder"> <img class="plant" alt="plant" id="plant1" src="./images/plant1.png" /> </div> <!-- plant2 ~ plant7 位于左容器,plant8 ~ plant14 位于右容器 -->- 玻璃罐区(
#terrarium):由jar-top(罐口)、jar-walls(罐壁,内含两条高光jar-glossy-long/jar-glossy-short)、dirt(泥土)和jar-bottom(罐底)四类 div 分层拼出,详见 index.html。
值得注意的两个设计细节:
- 每株植物都有唯一 ID(
plant1~plant14),这是后面 JavaScript 用document.getElementById()精确绑定拖拽逻辑的前提——ID 用于个体定位,类名用于批量样式; - 脚本通过
<script src="./script.js" defer></script>在<head>中引用,defer保证 JavaScript 在 HTML 全部解析完毕后执行,避免"元素还没准备好就查找"的时序错误(该知识点在 DOM 与闭包课程 中有专门强调)。
3.2 CSS 样式:用纯 CSS 画出玻璃罐
style.css 除了常规布局,最精彩的是用层叠定位与透明度画出玻璃质感。核心思路可以拆成三层:
- 定位体系:
.container使用position: absolute钉在页面左右两侧(#left-container { left: 0; }、#right-container { right: 0; }),宽度 15%、高度 100%,形成两条"植物货架";.plant同样绝对定位并通过z-index: 2保证可被拖动到罐子上层,见 style.css; - 罐体层次:
.jar-walls占罐区 60% 宽、80% 高,border-radius: 1rem圆角,background: #d1e1df搭配opacity: 0.5呈现半透明玻璃感,z-index: 1介于背景与植物之间;.jar-top、.jar-bottom、.dirt分别用不同透明度(0.7 / 0.7 / 0.7)叠出罐口、罐底与泥土,z-index: -1的泥土让植物看起来"插在土里",见 style.css; - 高光细节:两条细长圆角白色条
.jar-glossy-long(宽 3%、高 20%)与.jar-glossy-short(宽 3%、高 5%)模拟玻璃反光,background: #ddfbff贴近真实玻璃的高光色。
此外,style.css 还补充了导航栏渐变背景(linear-gradient(90deg, #d1e1df 60%, #b2c9c6 100%))、hover 态过渡动画、页脚样式,以及@media (max-width: 700px)下导航栏纵向排列的响应式规则——注意这段代码位于.jar-*之后,是同一文件内的渐进式增强,符合课程"先画罐子、再补页面"的推进节奏。
3.3 JavaScript 拖拽系统:闭包 + Pointer Events
script.js 是整个项目交互的核心,其实现思路(dragElement + 闭包)源自 w3schools 的拖拽元素方案(文件头部有注释说明)。完整代码逻辑如下:
// 为全部 14 株植物绑定拖拽 dragElement(document.getElementById('plant1')); // ... plant2 ~ plant14 同样处理 function dragElement(terrariumElement) { // 闭包内的私有状态:四组坐标 let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; terrariumElement.onpointerdown = pointerDrag; function pointerDrag(e) { e.preventDefault(); // 阻止文本选中等浏览器默认行为 pos3 = e.clientX; // 记录按下点的 X pos4 = e.clientY; // 记录按下点的 Y document.onpointermove = elementDrag; // 移动时持续追踪 document.onpointerup = stopElementDrag; // 松开时停止 } function elementDrag(e) { pos1 = pos3 - e.clientX; // 水平位移增量 pos2 = pos4 - e.clientY; // 垂直位移增量 pos3 = e.clientX; // 更新基准点 pos4 = e.clientY; terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px'; terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px'; } function stopElementDrag() { document.onpointerup = null; // 清理,避免内存泄漏 document.onpointermove = null; } }结合 script.js 原文,这套系统有三个值得深挖的技术点:
1. 闭包即"私有状态仓"。每次调用dragElement(plantN)都会为那一株植物创建一份独立的词法环境,pos1~pos4相当于该植物私有的坐标记录。14 次调用产生 14 个互不干扰的闭包实例,这正是 DOM 与闭包课程 中"每株植物拥有自己的数据记录"这一教学目标的代码级落地。
2. Pointer Events 一统鼠标与触屏。事件链为onpointerdown(按下)→document.onpointermove(移动)→document.onpointerup(松开)。相比传统onmousedown(仅桌面鼠标)或onclick(无法表达持续拖动),Pointer Events 天然兼容鼠标、手指与触控笔。把移动/松开监听挂在document上而非元素自身,可保证指针快速移出植物甚至移出浏览器窗口时拖拽仍不中断。
3. 坐标数学与事件清理。clientX/clientY是相对视口的坐标;elementDrag通过"当前位置 - 上一次位置"算出增量,再用offsetTop/offsetLeft(元素相对定位祖先的偏移)叠加成新的top/left,实现"元素跟随指针平滑移动"。stopElementDrag将两个 document 级监听置空,是防止事件监听器累积导致性能劣化的关键收尾——教学文档特别强调过不清理的后果(监听器持续运行、资源浪费、元素行为异常),详见 课程第 3 节。
3.4 本地运行与体验
由于是纯静态项目,运行方式零成本:
- 直接双击/拖拽 3-terrarium/solution/index.html 到浏览器打开(本地文件协议即可,无需服务器);
- 或者在工作目录下起一个简易静态服务器(如
python -m http.server)后访问对应端口; - 按住任意植物 → 拖动 → 松开,即可完成一次布置;项目没有设计"落点限制",用户可以自由发挥创意摆放。
四、把项目发布到公网:Azure Static Web Apps 部署指南
部署是 solution README 明确给出的核心操作流程,也是本项目唯一涉及"上线"的章节。得益于应用无后端 API、无构建脚本的纯静态特性,整个部署过程可以在 Azure Static Web Apps 上做到"几乎零配置"。
4.1 三步部署流程
按文档指引,部署只需三步:
Fork 本仓库:先在平台侧把 Web-Dev-For-Beginners 仓库 Fork 到自己的账号下,以获得可写副本;
点击部署按钮:在 solution README 的部署章节中点击 "Deploy to Azure" 按钮,跳转到 Azure 门户的 Static Web Apps 创建向导;
走完创建向导:在向导中重点确认以下配置项——
配置项 推荐取值 说明 App root(应用根目录) /solution或你自己的代码根目录告诉构建服务去哪里找 index.htmlAPI 配置 跳过 本应用没有 API,无需配置 Azure Functions 等后端资源 构建产物 自动 仓库 Fork 后会自动生成 .github工作流文件夹,交给 Azure 构建服务完成构建与发布
文档特别说明(原文见 solution README 的 Deploy 一节):Fork 后仓库里会被创建.github文件夹,其中包含的 GitHub Actions 工作流会驱动 Azure Static Web Apps 的构建服务,自动把应用编译并发布到一个全新的公开 URL。也就是说,你无需手动编写任何 CI/CD 配置,只需完成上述三步。
4.2 部署原理补充
从仓库实际情况看,这套流程能够成立的关键在于两点:
- 无后端依赖:solution 目录 内只有
index.html、style.css、script.js与静态图片,不存在任何服务端接口调用,静态托管即可完整运行——这正是向导中可以安全跳过 API 配置的原因; - 根目录可配置:
App root指向/solution而非仓库根目录,是因为 Terrarium 只是 Web-Dev-For-Beginners 多课程仓库中的一个子项目,部署时精确指向子目录即可只发布本项目,避免把整个课程仓库全部托管出去。
补充说明:该部署入口同时出现在 Terrarium 课程主页 的 Deploy 小节,两处表述一致,可互为印证。
五、延展学习:从一个拖拽项目出发
完成部署后,项目本身仍是一片值得继续挖掘的试验田。依据 DOM 与闭包课程 的挑战清单,可以在不改动仓库的前提下,在自己的 Fork 上尝试以下增强,每一个都对应真实的 Web 开发知识点:
- 重置功能:新增一个按钮,点击后通过 CSS transitions 在 1 秒内把所有植物平滑送回两侧容器(涉及状态记忆与动画);
- 双击置顶:双击植物时修改其
z-index让它浮到最前(涉及样式属性动态写入); - 拖拽边界:限制植物不能被拖出罐子区域(涉及坐标计算与边界判定);
- 位置持久化:用
localStorage保存植物坐标,刷新后恢复布局(涉及浏览器存储 API); - 拖放反馈:悬停时增加微光效果、拾取/放置时播放音效(涉及事件监听与体验优化)。
这些练习都复用着本文讲解的同一套 DOM 操作、事件处理与状态管理模式,是通往看板拖拽、文件上传、图片排序等专业交互方案的必经之路。
结语
Terrarium 用最简的工程结构(1 个 HTML + 1 个 CSS + 1 个 JS + 14 张图片)演示了 Web 交互的完整闭环:HTML 定义结构、CSS 绘制界面、JavaScript 通过闭包与 Pointer Events 注入生命力,最后借助 Azure Static Web Apps 一键抵达公网。无论是作为 Web-Dev-For-Beginners 课程的学习终点,还是作为理解 DOM 与闭包的最小可运行范本,这个玻璃罐都值得亲手拖一拖、读一读它的三件套源码。
【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考