Framer CMS List:让一项内容成为可以增删、排序的整体
Framer 是可视化网站制作与发布工具。CMS List 让内容团队按行维护课程收获、常见问题或教程步骤,再用统一的卡片设计展示不断变化的内容。
先尝试拆解问题、设计和实现,再展开思路,检查状态、边界与取舍,并设计验证用例。思路提供分析路径,不给出完整实现。
01
界面实现进阶
重排、过滤与撤销时,怎样保留同一行的草稿?
练习场景
你在制作一个课程收获列表编辑器,每一行都有标题和说明。用户输入了尚未提交的文字,又把行拖到另一位置或用筛选暂时藏起来,这些文字仍应属于原来的行。“草稿”指未提交输入,“完整列表”包括被筛选隐藏的行,“撤销记录”保留最近删掉的一行。你要设计它们的状态归属,而不是实现拖拽组件。
已知条件与要求
用React/JS为自己的清单编辑器设计状态方案,保证用户编辑的是同一条内容,而非碰巧处于同一位置的输入框。只说明设计与验证,不写完整实现。
- 数据。 每行有全局唯一且永不复用的
rowId,以及标题和说明。允许标题相同。新增时生成ID,复制行必须产生新ID。容量上限为1,000条实体:当前完整列表中的行加上可撤销记录内保留的被删行共同计数;过滤不释放容量。不涉及服务器保存或多人并发。 - 草稿。 用户的未提交修改按行保留;重排或过滤不能使草稿串到其他行。过滤后的行会卸载,但恢复显示后其草稿还在。
- 删除与撤销。 每次只支持撤销最近一次删除;再次删除替换旧撤销机会。撤销窗口内允许修改、重排或新增其他行。恢复被删行时,先放在仍存在的原后邻之前;没有原后邻则放在仍存在的原前邻之后;两者都不在就放到末尾。原邻居按删除前完整列表记录,不按过滤结果记录。
- 编辑状态。 被删行的内容及草稿应随撤销恢复,复制行只复制当前可见文本,不共享后续编辑状态。新增或复制会使总实体数超过上限时,拒绝该操作并显示容量提示,现有内容、顺序和撤销记录都保持不变。有效删除可替换旧撤销记录并释放旧记录;撤销把记录中的实体移回列表,不增加总实体数。不同按钮动作如何影响可撤销记录需要说清楚。
- 说明与反例。 提出数据结构、React key及状态归属、无效操作处理和复杂度。至少用重排、过滤卸载、重复标题和删除后新建四种情况说明为什么不会串行;不需要实现拖拽、焦点管理或完整编辑器。
用这个情境检查你的方案
完整顺序为 A、B、C,A 和 B 标题相同。在 B 输入尚未提交的“练习反馈”,先重排成 B、A、C,再过滤隐藏 B 并恢复显示。接着删除 B、新增 D、撤销删除。请逐步标出 B 的身份、文字和位置,不能只看屏幕上的第几行。
需要交付什么
交付状态结构图、每种操作改变哪些状态的表,以及示例序列和容量边界的推演。解释 React key 能做什么、过滤卸载后还需要保存什么;不要求服务器、持久化或完整页面代码。
查看思路
- 将身份、顺序和显示子集分开。 可用
rowId索引行内容和草稿,用单独有序ID列表表达完整顺序。过滤只计算可见ID,不删除实体。React使用稳定的rowId作key,标题、数组下标或渲染时随机值都不是合适身份;依据见列表说明。 - 把需要跨卸载保留的内容放在列表级。 key能帮助匹配仍在树里的组件,但不能替已经卸载的组件保存本地state。React状态生命周期说明移除组件会丢弃其状态。草稿保留在列表级按ID索引,行组件接收对应值;新复制行创建独立实体。
- 把删除保存成一份有边界的撤销记录。 记录被删实体、草稿和原前后邻ID,然后从实体及顺序中移除。下一次删除替换记录;其他行的编辑、重排或新增保留它。撤销时按题目给定邻居优先级插入,消费记录,不能复用旧索引猜位置。不存在的目标或没有记录的撤销是无效操作,不改变现有状态。新增和复制先检查“当前行数+撤销保留实体数”,超过上限则拒绝,不能顺便丢掉撤销记录腾空间。
- 用最小状态序列检查。 A、B同标题,在B输入草稿后重排为B、A,草稿仍属于B;过滤B再恢复,草稿不丢。删除B后新增D,撤销恢复原B的ID与草稿,D不被覆盖。删除B再删除A后,只能撤销A;前一次记录占用的内容可以释放。复制B产生C,修改C不能同步改B。满1,000行时删除B,999条当前行加1条撤销实体仍占满容量,因此新增D被拒绝;撤销B后恰好恢复为1,000行。若不撤销B而接着删除另一行A,则旧B记录被释放,总实体数变为999,此时才可再新增一行。
- 界定代价与保证。 哈希索引按摊还常数访问,数组表达顺序时插入、删除、定位邻居及整轮过滤最坏O(n),保存实体、草稿、顺序与一条撤销记录为O(n)空间,文本总大小另计。不要把React渲染成本或输入字符处理说成恒定;此方案只保证本页状态语义,不提供跨刷新持久化。