ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Craft.js 的技术血统:react-dnd、GrapesJS 与 use-methods 的借鉴实践与源码验证

Craft.js 的技术血统:react-dnd、GrapesJS 与 use-methods 的借鉴实践与源码验证 前端【免费下载链接】craft.js A React Framework for building extensible drag and drop page editors项目地址https://gitcode.com/gh_mirrors/cr/craft.js点击查看免费下载这篇技术指南以 site/docs/acknowledgements.md 中官方致谢清单为线索逐条剖析 Craft.js 从 react-dnd、GrapesJSGrape.js与 use-methods 三个开源项目中借鉴的设计思路与实现细节并结合仓库源码验证每一条致谢背后的真实代码落点。读完本文你将掌握 Craft.js 拖拽连接器connector机制、元素落点定位算法、基于 immer patch 的撤销/重做历史记录这三块核心能力的来源与底层原理也能学会如何在源码层面核实一个框架技术血统的真实性。为什么一份致谢清单值得深挖Craft.js 是一个用于构建可扩展拖拽式页面编辑器的 React 框架。它不提供开箱即用的编辑器 UI而是模块化地提供拖放系统、节点渲染/更新/移动等基础能力让开发者用纯 React 方式搭建自己的编辑器见 packages/core/README.md。官方文档的致谢页虽然只有短短几行却精确地交代了这套系统三个最关键的技术来源react-dndReact 拖拽库。Craft.js 并未直接依赖它但以它为参考借用了部分工具函数与设计模式Grape.jsGrapesJSHTML 网页构建器框架是 Craft.js 的灵感来源其元素定位逻辑被直接借用use-methods处理 reducer 的实用 hookCraft.js 使用了经过修改的版本以适配自身 API。这份清单的价值在于它把借鉴了什么、借鉴到哪一层、是否直接依赖交代得非常清楚。下面我们逐一深入源码验证每一项致谢是否名实相符并还原这些设计如何转化为 Craft.js 的具体能力。react-dnd参考而非依赖借来的是连接器设计模式致谢原文明确说明react-dnd 虽未在 Craft.js 中被实际使用但 Craft.js 的许多方面以其为参考并借用了一些工具函数。这在源码中可以得到精确验证。借用的工具函数connector hook 包装在 packages/utils/src/EventHandlers/wrapConnectorHooks.tsx 的源码首行就保留了来源注释// https://github.com/react-dnd/react-dnd。这个文件实现了wrapConnectorHooks其核心逻辑与 react-dnd 的经典模式一脉相承wrapHookToRecognizeElement让一个原本接收 DOM 节点node的 hook 同时能接收 ReactElement——如果传入的是合法 React 元素就通过cloneWithRef克隆元素并把 hook 作为 ref 挂上去如果传入的是 DOM 节点则直接调用 hook。这带来一个非常顺滑的 API用户甚至不需要感知底层在用 ref。cloneWithRef克隆元素并合并新旧 ref若元素已有 ref 则包装成一个同时调用新旧 ref 的回调若旧 ref 是字符串 ref 则直接报错提示改用回调 ref。这正是 react-dnd 中同名的工具函数逻辑。这套把事件处理器包装成可链式调用的连接器connector的模式构成了 Craft.jsuseNode()/useEditor()中connectors: { connect, drag, ... }API 的基础。在 packages/utils/src/EventHandlers/EventHandlers.ts 中createConnectorsUsage()进一步把各个处理器统一注册到ConnectorRegistry支持延迟注册与批量清理让用户组件中的connect(drag(ref))这种链式写法成为可能。从参考到自研事件处理器体系值得强调的是Craft.js 并没有照搬 react-dnd 的 DnD 引擎而是自研了一套基于 DOM 原生拖拽事件dragstart/dragover/dragend等的事件处理体系packages/core/src/events/CoreEventHandlers.ts 定义了connect、select、hover、drag、drop、create六个核心处理器契约packages/core/src/events/DefaultEventHandlers.ts 给出默认实现包括点击选择/多选默认通过metaKey判定、hover 高亮、拖拽阴影createShadow、拖拽结束时的move/addNodeTree等底层由 packages/utils/src/EventHandlers/EventHandlers.ts 提供addCraftEventListener、事件冒泡阻断isEventBlockedByDescendant、reflect()兄弟连接器批量执行等通用机制。也就是说react-dnd 的贡献主要体现在连接器 API 的形态设计和若干工具函数上而完整的编辑器交互逻辑是 Craft.js 自己的实现——这与致谢中许多方面以 react-dnd 为参考的措辞完全吻合。GrapesJS灵感来源与元素定位算法的直接借用致谢提到 GrapesJS 为 Craft.js 提供了灵感且元素定位逻辑被借用。这条在源码中同样有明确的对应物。落点判定findPositionpackages/core/src/events/findPosition.ts 是元素定位的核心算法。它接收父节点及其子节点的几何信息top、left、outerWidth、outerHeight、inFlow 等结合鼠标位置posX/posY返回{ parent, index, where: before | after }形式的落点描述。算法要点包括计算每个候选元素的右边界left outerWidth、下边界top outerHeight、水平/垂直中心xCenter/yCenter对超出限制区域xLimit、yLimit、leftLimit的元素直接跳过对脱离文档流!inFlow如 float 元素的元素按中心点比较左右位置对正常流内元素鼠标位于其垂直中心上方则判定插入到其前before否则为后after。这段几何判定逻辑正是致谢所指的、从 GrapesJS 借用过来的元素定位逻辑。定位逻辑的调用链findPosition有两个实际调用方共同支撑拖拽放下的完整流程packages/core/src/events/Positioner.ts拖拽过程中由Positioner.computeIndicator()实时调用它把鼠标坐标换算成放置指示器indicator的位置packages/core/src/editor/query.tsx在查询层getDropAction一类的逻辑中复用它生成可执行的 drop 动作。配合 packages/core/src/events/DefaultEventHandlers.ts 中drop处理器对dragover事件的监听与setIndicator状态更新拖拽过程中的蓝色/红色落点指示、以及拖放结束后的move移动已有节点与addNodeTree创建新节点都由这套定位算法驱动。从源码结构看Craft.js 把这一借来的算法封装成独立模块并参数化NodeInfo、DropPosition接口使其既能服务拖拽指示器也能服务查询层动作计算是一次典型的借鉴算法、自建架构实践。use-methods一个 reducer hook 的深度改造第三条致谢指向 use-methods——一个处理 reducer 时非常好用的 hookCraft.js 使用了一个修改版以更好地适配自身 API。这条的技术含量最高因为它直接关系着整个编辑器状态管理EditorState的基石。改造后的 useMethods 在源码中的位置packages/utils/src/useMethods.ts 首行即保留来源注释// https://github.com/pelotom/use-methods。与上游相比Craft.js 的版本做了以下关键改造均可从源码确认基于 immer 的 patch 机制内部通过produceWithPatches产生patches与inversePatches并在文件顶部调用enableMapSet()、enablePatches()以支持Map/Set结构与 patch 追踪——这正是编辑器状态中SetNodeId类型字段如events.dragged、events.selected能被正确记录的前提内置 History 时间轴每个动作执行后除被忽略的动作外都会把 patches 写入 packages/utils/src/History.ts 的时间轴。该文件实现了undo/redo通过applyPatches回放 inverse/正向 patches、throttleAdd默认 500ms 节流合并连续动作、merge合并到上一条记录、clear以及canUndo/canRedo判断Options 形态除了直接传 methods 函数还支持传入{ methods, ignoreHistoryForActions, normalizeHistory }。ignoreHistoryForActions用于声明哪些动作不进入历史如下文中的setDOM、setIndicatornormalizeHistory则在每次 undo/redo 后对状态做一致性修正query 与 patchListener新增queryMethods参数生成只读查询接口含history.canUndo()/canRedo()以及patchListener回调在每次动作后把{ type, params, patches }通知给外部监听者。编辑器 store 的实际应用packages/core/src/editor/store.tsx 是改造版 useMethods 最典型的消费方return useMethods( ActionMethodsWithConfig, { ...editorInitialState, options: { ...editorInitialState.options, ...options } }, QueryMethods, patchListener ) as EditorStore;其中ActionMethodsWithConfig展示了 Options 形态的完整用法methods: ActionMethods全部状态变更动作如move、addNodeTree、setProp等ignoreHistoryForActions: [setDOM, setNodeEvent, selectNode, clearEvents, setOptions, setIndicator]这些与拖拽渲染临时状态相关的动作不污染撤销历史normalizeHistory在每次 undo/redo 后清理指向已删除节点的失效事件引用并同步state.events与state.nodes[id].events的一致性源码注释也坦言这种双份状态同步比较繁琐是已知的技术债务。该模式在配套包中同样被复用craftjs/layersPhotoshop 式图层面板也通过useMethods(LayerMethods, ...)构建自己的 manager store。从致谢清单看一个框架的工程取舍综合三条致谢与其源码证据可以提炼出 Craft.js 技术借鉴的三个工程原则借鉴 API 形态不依赖实现react-dnd 的 connector 包装模式被吸收进 wrapConnectorHooks.tsx但拖拽引擎完全自研见 DefaultEventHandlers.ts因此致谢用词是参考 借用工具函数而非依赖。借鉴算法自建封装GrapesJS 的元素定位思想被独立实现为 findPosition.ts再通过 Positioner.ts 与 query.tsx 两个出口接入编辑器事件与查询体系。深度改造第三方 hookuse-methods 被升级为immer patches 历史时间轴 查询接口 patch 监听的完整状态管理基座支撑 store.tsx 与 History.ts 的撤销/重做能力这也解释了为什么其输出类型命名为SubscriberAndCallbacksFor——它同时提供订阅、回调、查询与历史四类能力。如果你也想在源码层面核实这类致谢的真实性可以按本文的做法先在文档中找出被致谢的项目名再在仓库中搜索对应的文件名、注释本项目大量保留了// https://github.com/...形式的来源注释与调用点最后比对借用到哪一层与致谢措辞是否一致。这种文档—源码—措辞三方互证是理解开源项目技术血统最可靠的方式。结语一份看似简短的致谢清单实际上是 Craft.js 架构决策的浓缩索引react-dnd 贡献了连接器 API 的形态与工具函数GrapesJS 贡献了元素定位算法与产品灵感use-methods 则经过深度改造成为编辑器状态管理的底座。通过 site/docs/acknowledgements.md 提供的线索沿 packages/core 与 packages/utils 的源码逐条印证你不仅能更深刻地理解 Craft.js 的设计取舍也能把这套溯源验证的方法迁移到对其他开源框架的分析中去。赞分享前端【免费下载链接】craft.js A React Framework for building extensible drag and drop page editors项目地址https://gitcode.com/gh_mirrors/cr/craft.js点击查看免费下载相关推荐WeKan 设计演进史与 Trello、Jira 的功能借鉴对比与技术溯源WeKan 设计演进史与 Trello、Jira 的功能借鉴对比与技术溯源 导读 本文以仓库 docs/Design/Design WeKan Trello后端前端协同办公craft.js的单元测试Jest与React Testing Library实践craft.js的单元测试Jest与React Testing Library实践 测试环境配置 craft.js项目采用Jest作为测试运行器结合Reac前端Linly-Dubbing完整配置指南打造专业级AI视频配音工具Linly Dubbing完整配置指南打造专业级AI视频配音工具 想要为视频添加多语言配音Linly Dubbing是一款功能强大的AI配音工具能够实现智人工智能AI 应用大模型语音音频音视频数字人上一篇FreeMoCap动作捕捉终极指南7步快速解决常见问题与故障排除下一篇构建坚不可摧的活动目录安全防线WatchAD深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表