HomeworkHub:纯原生 HTML/CSS/JS 作业小程序与 AI 批改规则引擎实践

举报
yd_266360277 发表于 2026/11/09 00:15:09 2026/11/09
【摘要】 HomeworkHub是华为云海客松作品:纯原生HTML/CSS/JS的学生作业收集整理小程序,用localStorage做数据持久化,打通教师发布批改、学生做题提交、家长查看错题本三端,并内置AI批改规则引擎,本文详解其架构、数据模型与鸿蒙迁移思路。

HomeworkHub:用纯原生 HTML/CSS/JS 做学生作业收集整理小程序

写在前面:一个海客松作品的诞生

HomeworkHub 是我在华为云海客松上做的一个学生作业收集整理小程序。它的目标很具体:解决老师、学生、家长三方在作业这件事上的信息断层。老师发布作业靠群消息,学生交作业靠拍照,家长想知道孩子错在哪里,只能翻聊天记录。一个作业从布置到批改再到订正,链路长、易丢失、难复盘。

我们选择的解法反其道而行之:不引入任何框架和后端服务,只用纯原生 HTML、CSS、JavaScript 做一个单页小程序,用 localStorage 做数据持久化,把教师发布与批改、学生做题与提交、家长查看错题本三条链路装进一个应用里,再加一个轻量的 AI 批改规则引擎做自动初判。本文记录这套方案的设计思路、核心实现与踩过的坑。

一、产品定位:三端一体,而不是三个应用

很多作业类产品把教师端、学生端、家长端拆成三个应用,开发成本高,使用门槛也高。HomeworkHub 只做一个应用,顶部切换角色:

  • 教师端:发布作业、查看提交情况、逐题批改、导出错题统计。
  • 学生端:查看待做作业、在线做题、提交答案、查看批改结果与错题。
  • 家长端:只读查看孩子的作业完成情况与错题本,不改任何数据。

三端共用同一套数据模型,只是视图与权限不同。这样做的好处是:一个文件就能跑通完整闭环,演示时不用准备服务器;坏处是权限只靠前端角色切换,适合校内演示与小范围使用,不适合直接上生产。后文会讲到如何把这套模型平滑迁移到端云一体架构。

二、技术选型:为什么坚持纯原生

选型时我们认真比较过三种路线:第一是上框架加后端,第二是用低代码平台,第三是纯原生三件套。最终选了第三种,理由有四点。

第一,零部署成本。海客松现场网络与时间都有限,一个 index.html 加几个静态文件,双击就能打开,不依赖构建工具,不怕 npm 装不上。第二,启动快、好调试。原生 DOM 操作直观,出现问题直接在浏览器控制台定位,到哪一步卡住一目了然。第三,数据可控。localStorage 就在浏览器本地,断网也能用,适合教室、家庭等网络不稳定的场景。第四,便于做鸿蒙适配。原生 Web 能力与 HarmonyOS 的 Web 组件、ArkTS 思想在组件化、状态管理上有很多相通之处,先把逻辑跑通,再迁移界面,路径更清晰。

当然纯原生也有代价:没有路由、没有状态管理库,所有状态都要自己维护;DOM 拼接字符串容易出错;多人协作、跨设备同步天然缺失。我们的对策是把应用拆成清晰的模块:state.js 管状态与持久化,render.js 管渲染,rules.js 管批改规则,ui.js 管交互,四个文件各司其职,互相只通过约定的数据结构通信。

三、总体架构:一个单页应用的四层结构

HomeworkHub 的运行结构可以概括为四层。视图层是 HTML 骨架加 CSS 样式,负责三端界面的切换与展示;交互层是事件委托与表单校验,负责点击、输入、提交;业务层是作业、题目、提交记录、错题本四个核心实体及其流转规则;数据层是 localStorage 的读写、版本迁移与备份导出。

页面加载时,应用先读 localStorage 里的数据快照,恢复成内存中的 state;用户每次操作先改内存 state,再写回 localStorage;渲染函数根据 state 重绘当前角色视图。这种单向数据流是整个应用最关键的设计:界面永远是数据的投影,数据出错时只要看 state 就能定位,界面再乱也乱不到数据层。

四、数据模型:作业、题目、提交与错题

数据模型是这个小程序的骨架。我们定义了四张逻辑表,全部存在 localStorage 的一个根键 homeworkhub_v1 下:

{
  "version": 1,
  "assignments": [{ "id": "a1", "title": "数学第五章练习", "subject": "数学", "deadline": "2026-11-10", "questions": ["q1", "q2"] }],
  "questions": [{ "id": "q1", "type": "choice", "stem": "3+5=", "options": ["6", "7", "8", "9"], "answer": "8", "score": 5 }],
  "submissions": [{ "id": "s1", "assignmentId": "a1", "student": "小明", "answers": { "q1": "8" }, "status": "graded", "totalScore": 5 }],
  "mistakes": [{ "student": "小明", "questionId": "q1", "wrongAnswer": "7", "times": 2 }]
}

题目支持四种题型:选择题、填空题、判断题、简答题。选择题与判断题可以自动判分,填空题用规则引擎判分,简答题先由规则引擎给参考分,再由教师人工确认。这种分级处理既保证了自动化效率,也保留了人工兜底。

错题本不是单独录入的,而是从提交记录中自动生成的:学生答错的题,提交后自动写入 mistakes,times 字段累计错的次数。家长端按学生筛选错题,按科目与知识点分组,按错误次数排序,错得越多的题排得越靠前,复习优先级一目了然。

五、localStorage 持久化:小而关键的五个细节

localStorage 看似简单,用好它有五个细节。第一是读写封装:所有读写走同一个 storage 模块,JSON 序列化与反序列化集中处理,解析失败时返回空数据而不是让页面白屏。第二是版本字段:根对象带 version,升级数据结构时写迁移函数,老数据自动升级。第三是写节流:输入框每敲一个字就写一次会很卡,我们的做法是内存先改、失焦与提交时再落盘。第四是容量意识:localStorage 一般只有 5MB 左右,错题与提交记录增长快,要定期归档,导出 JSON 备份后清理旧数据。第五是隐私提示:数据存在本机浏览器,换设备就看不到,演示时要说明这一点,避免误以为数据丢了。

const KEY = 'homeworkhub_v1';
function save(state) {
  try { localStorage.setItem(KEY, JSON.stringify(state)); }
  catch (e) { alert('本地存储空间不足,请先导出备份再清理旧数据'); }
}
function load() {
  try { return JSON.parse(localStorage.getItem(KEY)) || emptyState(); }
  catch (e) { return emptyState(); }
}

六、教师端:发布与批改的完整闭环

教师发布作业只需要三步:填标题与科目、加题目、设截止时间。题目支持从题库中复用,也可以现场新增。发布后作业立即出现在学生端待办列表里,按截止时间排序,快到期的标红提醒。

批改界面按学生分组,每道题显示学生答案、标准答案与规则引擎给出的初判分数,教师可以一键采纳,也可以改分并写评语。改分后总分自动重算,错题同步更新到错题本。教师还能看到全班的错题统计:哪道题错得最多、哪个知识点最薄弱,下一次讲评就有了依据。

这里有一个细节:提交后学生不能再改答案,但可以查看已批改的结果。状态机只有四种状态:未提交、已提交待批改、已批改、已订正。状态流转全部由函数控制,不允许界面直接改状态,这是避免数据错乱的关键。

七、学生端与家长端:做题、提交与错题本

学生端的主界面就是一张待办清单:今天要做的作业、每科的截止时间、完成进度。点进一道作业,逐题作答,答案实时保存在内存里,提交前可以反复修改。提交时先做校验:有没有漏题、填空题有没有空着,校验不通过会定位到第一道未答的题,而不是笼统地报错。

提交后学生能看到每道题的对错、得分与解析,错题自动进入我的错题本。错题本支持按科目筛选、按错误次数排序,还能一键生成错题重练:把错题抽出来重新做一遍,做对了错题次数清零,做错了次数加一。这种刻意练习的循环,比 단순抄错题有效得多。

家长端是只读视图:看得到孩子的完成率、得分趋势与错题清单,看不到其他学生的数据,也改不了任何内容。家长最关心的问题其实只有一个:孩子到底卡在哪里。错题本按知识点归类后,这个问题就有了答案。

八、AI 批改规则引擎:没有大模型,也能自动批改

这是 HomeworkHub 最有意思的部分。没有调用任何大模型接口,批改规则引擎就是一套可配置的规则集合,跑在浏览器本地:

  • 精确匹配:选择题与判断题直接比对标准答案。
  • 归一化匹配:填空题先去掉首尾空格、全角转半角、统一大小写,再比对,容忍格式差异。
  • 数值容差:数学题允许正负 0.01 的误差,分数、小数、百分数等价换算后也算对。
  • 关键词规则:简答题按命中关键词给分,命中核心概念给满分,命中部分概念给部分分,没命中给零分并提示缺失点。
  • 正则规则:英语填空、日期、单位换算等场景用正则表达式做模式匹配。

每条规则都返回三样东西:得分、判定结果、反馈文案。反馈文案比分数更重要:告诉学生错在哪里、为什么错、应该看哪个知识点。规则由教师在发布作业时配置,存在题目的 rules 字段里,改规则不需要改代码。

function gradeFill(question, answer) {
  const norm = s => String(s || '').trim().replace(/,/g, ',').toLowerCase();
  if (question.tolerance) {
    return Math.abs(Number(answer) - Number(question.answer)) <= question.tolerance;
  }
  return question.acceptAnswers.some(a => norm(a) === norm(answer));
}

这套引擎的边界也要说清楚:它判不了开放式作文,也理解不了学生的解题思路,只能做规则范围内的初判。简答题与论述题永远保留教师人工确认环节,规则引擎只给参考分,不给最终分。把 AI 的定位定在助手而不是裁判,是这个设计最重要的一点。

九、界面与交互:CSS 写界面,事件委托管交互

界面用 CSS Grid 做三端布局,Flex 做卡片排列,响应式断点只有两个:桌面端三栏,移动端单栏。配色克制,作业状态用颜色区分:待做是蓝色,已提交是黄色,已批改是绿色,逾期是红色,一眼就能看到状态。

交互上坚持一个原则:所有列表的点击都用事件委托,挂在父容器上判断目标元素,而不是给每个按钮单独绑事件。这样动态渲染出来的新按钮也能正常工作,也避免了重复渲染后事件丢失的问题。我们在联调时吃过这个亏:直接给按钮绑事件,重新渲染后按钮就点不动了,改成事件委托后问题消失。

十、向 HarmonyOS 迁移的思路

HomeworkHub 现在是 Web 小程序,迁移到 HarmonyOS 的路径是清晰的。界面层可以用 ArkTS 重写,@State 管理 state,@StorageLink 做跨页同步;数据层把 localStorage 换成 Preferences 做本地持久化,把云端同步换成云函数加云数据库;规则引擎是纯 JavaScript 逻辑,几乎不用改就能复用。

更长远的形态是元服务:家长不用安装应用,搜一下就能打开错题本;教师在手机上发布作业,学生在平板上做题,数据通过云端同步。这条路在海客松的答辩里得到了评委的认可,也是我们下一步想做的事。迁移时最需要注意的是:先把数据模型与业务规则原样搬过去,不要在迁移时顺手改逻辑,界面与数据分开验证。

十一、踩坑复盘:五个真实教训

第一,localStorage 只能存字符串,存对象必须 JSON.stringify,取出来必须 JSON.parse,忘记任何一步都会得到 [object Object]。第二,id 一定要用时间戳加随机数生成,用数组下标做 id,删一道题后所有引用都会错位。第三,渲染函数不要直接拼用户输入进 innerHTML,学生姓名与答案里可能有特殊字符,要先转义。第四,截止时间要存 ISO 字符串,不要存本地时间文本,跨时区会乱。第五,演示前一定要准备一份演示数据,现场从零录入数据会浪费大量时间,还容易出错。

十二、总结

HomeworkHub 证明了一件事:一个小而完整的应用,不需要重型技术栈也能把一件事做透。纯原生 HTML、CSS、JavaScript 加 localStorage,足够跑通作业的发布、做题、提交、批改、错题全链路;一个轻量规则引擎,足够完成大部分题型的自动初判;一个清晰的数据模型,足够支撑向 HarmonyOS 端云一体架构的迁移。

如果你也在做类似的教育类小程序,建议从数据模型先入手,把作业、题目、提交、错题四张表想清楚,再写界面;规则引擎先做精确与归一化匹配,再加容差与关键词,别一上来就想做语义理解;最后留好迁移接口,本地能跑通的东西,上云与上端才跑得通。完整代码与演示数据后续会整理到代码仓,欢迎交流。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。