首页
/ Web-Dev-For-Beginners Terrarium 项目实战:选一个 DOM 接口深入调研的“DOM 进阶作业”怎么做

Web-Dev-For-Beginners Terrarium 项目实战:选一个 DOM 接口深入调研的“DOM 进阶作业”怎么做

2026-09-04 14:22:26作者:郦嵘贵Just

本篇指南围绕 Web-Dev-For-Beginners 课程 Terrarium(生态瓶)项目的第三部分课后作业“再与 DOM 深入合作”展开:从 MDN 的 DOM 接口清单中挑选一个接口,找到真实网站中的使用案例,并写出带代码示例的使用说明。读完本文,你将完整拿到这份作业的原始要求与评分标准,了解本项目拖拽实现中已经用到的全部 DOM 接口作为调研起点,并能按可落地的三步路线(选题、调研、成文)交出一份符合评分要求的作业。

DOM 树结构示意图:文档对象模型与 HTML 标记的层级关系

作业定位:它属于课程的哪个环节

Terrarium 项目分三课递进:第 1 课搭 HTML 骨架、第 2 课做 CSS 样式、第 3 课用原生 JavaScript 实现“把植物拖进瓶子”的交互。第 3 课的正文在 课程 README 中,结尾的 Assignment 小节直接指向本作业;仓库中的韩文版作业说明位于 assignment.ko.md,英文完整版位于 assignment.md

这份作业的意义在于“从点到面”:你在课堂上刚刚亲手用过一小撮 DOM API(取元素、监听指针事件、改样式位置),而作业要求你跳出这一个项目里出现过的接口,到 MDN 的 DOM 接口清单中去“认领”一个更宽泛的接口,调研它在真实网站中是怎么被使用的,并写出自己的使用说明。这是从“会用几个 API”走向“理解整套 DOM 能力版图”的一步。

完成拖拽功能后的 Terrarium 最终效果:植物可被拖入瓶中任意摆放

原始作业要求与评分标准(完整继承)

韩文版作业原文只有两个部分,要求非常明确,这里完整保留其内容:

说明(설명):认领(채택)一个 DOM 元素/接口,对 DOM 做进一步调研。访问 MDN 的 DOM 接口清单 页面并从中选择一个接口,然后在网上找到一个正在使用它的网站,针对该用法撰写一份说明文档。

评价标准(평가 기준)

기준(维度) 模范答案 合适的答案 需要改进的答案
(未单列维度名,按“成文质量”整体评估) 以段落形式撰写,且带有示例 以段落形式撰写,但没有示例 没有任何记录

从这张表可以读出作业的核心判分点:答案必须是段落式的解释文字(而不是只贴一串代码或一堆链接),并且必须附带具体示例;只有“记录”而不带例子的答案会被降级。

英文完整版 assignment.md 对同一份作业给出了更细的五个维度评分细则,可以作为更严格的自查参照:

维度 模范(A) 合格(B) 发展中(C) 需改进(D)
技术理解 解释准确、术语规范,体现深入理解 理解扎实、大体准确 基础理解,存在少量误解 理解有限,错误明显
真实案例分析 找到并深入分析真实实现,有具体例证 找到真实案例,分析充分 找到了案例但分析浮于表面 现实关联含糊或不准
代码示例 可运行、注释完善、清晰演示接口 功能正确、注释充分 能跑但文档不足 代码有错误或解释混乱
写作质量 结构清晰、表达生动、技术沟通规范 组织良好 组织尚可 组织混乱或表达不清
批判性思考 能洞察概念间的联系并提出创新应用 分析到位、联系相关 有一些分析但不够深 批判性思考证据不足

调研起点:Terrarium 项目已经用过哪些 DOM 接口

做这份作业最省力的切入方式,是先盘点“自己项目里已经用到的 DOM 接口”,再向外圈扩展。从参考答案 script.js 的源码看,拖拽系统共动用了下面这些接口与属性,它们都天然适合作为你撰写调研文档时的对照组:

接口 / 属性 在代码中的位置 作用
document.getElementById() script.js L3-L16 连续 14 次调用 按 id 取回 plant1plant14 元素
Element.onpointerdown script.js L29 terrariumElement.onpointerdown = pointerDrag; 按下植物时触发拖拽起始
Event.preventDefault() script.js L32 阻止默认行为(如拖拽过程中选中文字)
Event.clientX / Event.clientY script.js L35-L36L46-L52 读取指针相对视口的坐标
document.onpointermove / onpointerup script.js L38-L40L59-L63 挂在 document 上,保证指针移出元素后仍能持续追踪
Element.offsetTop / offsetLeft script.js L55-L56 读取元素相对定位祖先的当前位置
Element.style.top / style.left script.js L55-L56 用内联样式更新元素位置,实现“跟手”

此外还有两个容易被忽略但同样属于 DOM 知识面的细节:

  • defer 脚本加载策略index.html L13 使用 <script src="./script.js" defer></script>,确保 HTML 解析完成后脚本才执行,从而保证 getElementById('plant1') 这些调用执行时 14 个 <img id="plantN"> 节点已经存在。
  • CSS 定位前提offsetTop/offsetLeft 是相对“最近的定位祖先”计量的,而 style.css.plant 声明了 position: absolute、外层 .plant-holder.container 均为绝对/相对定位——JavaScript 的拖拽数学只有在这套 CSS 前提成立时才正确。写调研文档时,这类“API 与样式层联动”的细节正是区分“合适答案”和“模范答案”的加分内容。

script.js L18-L64 的闭包结构还能看出一个设计模式:dragElement(terrariumElement) 每次被调用都会生成一组私有的 pos1pos4 变量和三个内部函数(pointerDragelementDragstopElementDrag),14 株植物因此各自维护互不干扰的坐标状态。你的调研主题如果选到 classListquerySelector 等接口,可以顺带对比“本项目为何选择按 id 逐个取元素”而不是“用 querySelectorAll('.plant') 一次取全部”——这种对比本身就是英文作业模板里“Practical Application(与 terrarium 技术做对比)”部分要考察的内容。

作业完成的三步实操路线

以下路线依据英文版 assignment.md 的 Step 1~Step 3 整理,每一步都给出可直接照做的操作。

第一步:选一个 DOM 接口

打开 MDN 的 DOM 接口清单页面(即作业说明中给出的那个入口),从中挑一个。英文版作业按难度给了三档候选,可对照选择:

  • 入门友好Element.classList(动态管理 CSS 类)、Document.querySelector()(进阶元素选取)、Element.addEventListener()(指针事件之外的事件处理)、Window.localStorage(客户端数据持久化)
  • 中级挑战Intersection Observer API(检测元素可见性)、MutationObserver(监听 DOM 变更)、Drag and Drop API(本项目指针方案之外的另一种拖拽路线)、Geolocation API(获取用户位置)
  • 进阶探索Web Components(自定义元素与 Shadow DOM)、Canvas API(程序化绘图)、Web Workers(后台线程)、Service Workers(离线能力)

选题建议遵循两条原则:一是选一个与 Terrarium 已用接口形成对照的(比如你用过 getElementById,就可以挑 querySelector 系来对比选取方式;你用过指针事件,就可以挑 Drag and Drop API 来对比拖拽实现路线);二是选一个你手头能立刻打开 DevTools 验证的,避免选到需要特殊硬件或权限的接口(如 Geolocation)导致无法给出可运行示例。

第二步:调研真实网站的实现

作业要求“在网上找到一个正在使用它接口的网站”,操作要点:

  1. 打开目标网站,按 F12 进入浏览器开发者工具;
  2. 在 Console 中用该接口做探测,例如 localStorage.getItem('某键名') 看是否有返回、document.querySelectorAll('某选择器').length 看选取规模,以此确认站点确实在使用这个能力;
  3. 在 Network/Source 视图中搜索接口关键字(如 addEventListenerIntersectionObserverlocalStorage),定位到具体是哪段代码在调用;
  4. 记录三件事写进文档:开发者为什么选这个方案(例如用 IntersectionObserver 做懒加载是因为滚动监听开销大)、它如何改善用户体验(例如首屏图片延迟加载减少白屏)、以及你找到的代码片段

第三步:撰写说明文档并附上可运行代码示例

英文版作业给出的提交结构模板如下,照此组织你的文档:

# [接口名] DOM 调研

## What It Does(技术概述)
用初学者能懂的语言定义该接口,说明它提供的关键方法/属性/事件,以及它要解决的问题

## Real-World Example(真实案例分析)
你找到的网站、具体实现细节(尽量附代码片段)、开发者选型动机、用户体验收益

## Code Demonstration(代码演示)
一个带注释、可运行、贴近真实场景的最小示例

## Reflection(反思)
该接口与 terrarium 项目技术的联系、如何扩展 terrarium、还有哪些项目适合用它

字数要求为 300~500 词;代码示例必须满足四个条件:功能可跑通、逐段有注释、与真实用例相关、初学者能读懂。写作上注意用“给朋友讲”的口吻而不是照抄文档,且每个技术结论尽量配一个具体例子——这正好对应韩文版评分表中“带示例的段落”这一模范答案标准。

下面给出一个贴合本项目结构的参考示例(localStorage 保存植物布局),可直接在 terrarium 的 script.js 中拖拽系统完成后追加测试:

// —— Window.localStorage 示例:记住用户摆放好的植物位置 ——
const STORAGE_KEY = 'terrarium-plant-positions';

// 页面加载时恢复:读取上次保存的布局并写回内联样式
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
for (const id of Object.keys(saved)) {
  const el = document.getElementById(id); // 与主程序相同的按 id 取元素方式
  if (el) {
    el.style.top = saved[id].top;
    el.style.left = saved[id].left;
  }
}

// 页面卸载前保存:遍历 14 株植物,记录当前 top/left
window.addEventListener('beforeunload', () => {
  const positions = {};
  for (let i = 1; i <= 14; i++) {
    const el = document.getElementById('plant' + i);
    if (el) positions['plant' + i] = { top: el.style.top, left: el.style.left };
  }
  localStorage.setItem(STORAGE_KEY, JSON.stringify(positions));
});

验证方式:拖动几株植物后刷新页面,若布局保持原样即生效;在 DevTools 的 Application → Local Storage 中可看到 terrarium-plant-positions 键值。若你选的是 querySelector + classList 组合,也可以写更小的示例:

// 用 querySelectorAll 一次取回全部植物,点击切换高亮类
const plants = document.querySelectorAll('.plant');
plants.forEach((plant) => {
  plant.addEventListener('click', () => plant.classList.toggle('highlighted'));
});

这个示例同时演示了“批量选取”与“动态类名管理”两个入门接口,适合作为作业中“入门友好”档位的演示素材。

对照评分表的交付前自查清单

交作业前,用韩文版评分标准逐条对照,避免掉进“没有记录”或“只有段落没有示例”两档:

  1. 是否为段落式说明:四个小标题下是否都是成段解释,而不是只贴 API 签名或代码?
  2. 是否带具体示例:文中是否至少有一个真实网站案例 + 一段可运行代码?(这是模范答案与合适答案的分界线)
  3. 接口名称与 MDN 是否一致:如 Intersection Observer 的接口对象是 IntersectionObserverlocalStorage 挂在 Window 下——术语错误在英文版评分表中直接拖累“技术理解”维度;
  4. 代码是否真的测过:在浏览器里跑一遍,确认注释与实际行为相符;
  5. 是否建立了与 terrarium 的对照:Reflection 部分说明该接口如何扩展本项目(例如用 localStorage 保存布局、用 MutationObserver 监听植物增删),这是五维细则中“批判性思考”的得分点。

完成这份作业后,你对 DOM 的认知结构就从“我会拖拽”升级为“我知道 DOM 提供了哪些接口、它们各自解决什么问题、以及真实项目如何选型”——这正是从课程项目走向独立开发项目的关键一步。

仓库内延伸阅读路径:作业原文 assignment.ko.md、英文版 assignment.md、课程正文 README.md、参考实现 script.jsindex.htmlstyle.css

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391