用纯前端写一个可拖拽任务看板:原生 DnD、localStorage 与发布上架全流程

举报
yd_236761662 发表于 2026/10/23 09:45:51 2026/10/23
【摘要】 不引入任何框架,用 400 行 HTML/CSS/JS 做完一个三列看板:拖拽换列、分类筛选、本地持久化;并记录把作品发布到华为云开发者作品展览馆时踩到的几个点(封面 16:9、envUrl 可选、preflight 门禁)。

一、为什么手写而不是上框架

需求很简单:三列看板、拖拽换列、按分类筛选、刷新不丢数据。为这点东西引入构建链和依赖,收益为负。所以直接用原生 HTML + CSS + 一份闭包里的 JS,双击 index.html 就能跑,部署时也只需要一个静态目录。

二、数据模型:一个数组 + 三个状态

整个应用的状态只有三样:任务数组、当前筛选分类、正在拖拽的任务 id。任务本身是 { id, title, desc, category, status, createdAt },status 取值 todo / doing / done。渲染函数每次全量重建三列的卡片列表——在这个数据量级下,全量重绘比做增量 diff 简单得多,也不会出现状态不同步。

三、原生拖拽:四个事件 + 一个兜底

HTML5 Drag and Drop 的核心就四个事件:卡片上 dragstart,列容器上 dragenter/dragover(必须 preventDefault(),否则不会触发 drop),最后 drop。我踩的坑是:如果只在 dragstart 里记住「正在拖谁」,一旦中途 dragend 提前触发,这个变量就被清空,drop 时拿不到 id。

解决办法是双保险——dragstart 时同时把 id 写进 dataTransfer,drop 里优先读状态变量、读不到再读 dataTransfer:

card.addEventListener("dragstart", (e) => {
  draggingId = task.id;
  e.dataTransfer.effectAllowed = "move";
  e.dataTransfer.setData("text/plain", task.id);
});

zone.addEventListener("drop", (e) => {
  e.preventDefault();
  const id = draggingId || e.dataTransfer.getData("text/plain");
  if (id) moveTask(id, status);
});

另外 dragover 里只加 class 做高亮,不要在 dragover 里改数据——它触发频率很高,改数据会导致重绘抖动。

四、localStorage 要当成可能失败的东西

隐私模式、存储配额满、被浏览器策略禁用,都可能让 setItem 直接抛异常。读写都包 try/catch,存不进去最多是刷新后丢数据,不会白屏:

function save() {
  try { localStorage.setItem(KEY, JSON.stringify(state.tasks)); }
  catch (e) { /* 存不下就算了,不影响使用 */ }
}

五、发布到作品展览馆时要注意的几点

把作品提交到华为云开发者作品展览馆,流程上踩到几个值得记的点:

  1. 封面按 16:9 准备,1280×720 最稳;比例不对会在门禁那一步被打回。
  2. 线上体验地址 envUrl 是可选的,默认空串也能发布。作品只有静态页面、暂时没有公网地址时不必卡在这。
  3. 代码仓库要能公开访问,并且分支名要填对;详情包(zip)里建议放一份 README + 架构图。
  4. 提交前先在本地起服务验证一遍(python3 -m http.server),确认页面能开、资源 200,再走投稿。

六、小结

这类小工具的正确做法是「少即是多」:不打包、不引框架、状态只有一个数组,天然好调试;真正花时间的是拖拽的事件时序和发布时的材料准备,而不是功能本身。代码已经公开在 Code 仓,按需取用。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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