Blockly 类型化变量模态框插件 @blockly/plugin-typed-variable-modal 集成指南
Blockly 类型化变量模态框插件 blockly/plugin-typed-variable-modal 集成指南【免费下载链接】blocklyThe web-based visual programming editor.项目地址: https://gitcode.com/gh_mirrors/bl/blockly本指南围绕 Blockly 官方插件 blockly/plugin-typed-variable-modal 展开讲解如何为 Blockly 工作区打造一个创建类型化变量的模态对话框用户点击自定义按钮后弹出对话框输入变量名并从预设类型如 PENGUIN、GIRAFFE中单选一种确认后由插件自动完成变量创建与重名冲突校验。读完本文你将掌握该插件的安装、自定义动态 Flyout 集成、六类消息的国际化定制以及其背后依赖 Blockly 动态变量系统的完整实现原理。插件定位与依赖关系Typed Variable Modal 是 Blockly 生态中的一个官方插件核心能力是为带类型的变量typed variable提供创建入口。与 Blockly 内置的创建变量弹窗不同它允许开发者预先定义一组业务类型如动物、颜色、单位等用户创建变量时必须从中选择一种类型从而在编程积木层面实现类型约束。从 package.json 可以看到它的依赖关系peerDependenciesblockly ^13.2.0即要求宿主应用使用 Blockly 13.2 及以上版本dependenciesblockly/plugin-modal ^13.3.0模态框的基础 UI 能力遮罩、关闭按钮、焦点管理由通用 Modal 插件提供构建与测试基于blockly/dev-scripts、blockly/dev-tools、mocha、sinon、jsdom等。源码入口为 src/index.js它只做了一件事——export * from ./TypedVariableModal核心类TypedVariableModal定义在 src/TypedVariableModal.js该类直接extends Modal来自blockly/plugin-modal并覆写了渲染、确认、清理等关键生命周期方法。安装通过 npm 安装到你的 Blockly 项目npm install blockly/plugin-typed-variable-modal --save该命令会同时安装其依赖blockly/plugin-modal并自动校验 peer 依赖blockly版本是否满足^13.2.0。快速集成从工具箱到弹出模态框插件的集成不是简单实例化一个类而是需要配合Blockly 动态 Flyout自定义工具箱分类一起工作。核心思路是在工具箱中声明一个custom分类用回调动态填充该分类的 Flyout 内容包含一个触发按钮和已有的变量积木再把这个按钮回调与TypedVariableModal绑定。整个流程分为五步。第一步创建工作区import * as Blockly from blockly; import {TypedVariableModal} from blockly/plugin-typed-variable-modal; workspace Blockly.inject(blocklyDiv, { toolbox: toolbox, });第二步在工具箱中添加自定义分类在工具箱 XML或 JSON中声明一个带custom属性的分类custom的值是一个自定义回调名例如CREATE_TYPED_VARIABLEcategory nameColours customCREATE_TYPED_VARIABLE/categorycustom分类的内容完全由注册的回调函数动态生成这是 Blockly 官方文档所述dynamic flyout category的标准用法。第三步定义 Flyout 内容回调回调负责组装该分类在 Flyout 中显示的元素先推入一个按钮再追加Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace)返回的现有变量积木列表const createFlyout function (workspace) { let xmlList []; // Add your button and give it a callback name. const button document.createElement(button); button.setAttribute(text, Create Typed Variable); button.setAttribute(callbackKey, callbackName); xmlList.push(button); // This gets all the variables that the user creates and adds them to the // flyout. const blockList Blockly.VariablesDynamic.flyoutCategoryBlocks(workspace); xmlList xmlList.concat(blockList); return xmlList; };其中button的callbackKey就是后续要注册的按钮回调名下文的callbackName点击该按钮时工作区会调用这个回调名对应的函数。Blockly.VariablesDynamic.flyoutCategoryBlocks定义在 packages/blockly/core/variables_dynamic.ts它遍历workspace.getVariableMap().getAllVariables()按名称排序后为每个变量生成variables_get_dynamic取积木并额外生成一个带 24px 间距的variables_set_dynamic赋值积木。这意味着用户每次通过模态框创建的新变量都会自动出现在该分类的 Flyout 中形成创建即用的闭环。第四步注册工具箱分类回调workspace.registerToolboxCategoryCallback( CREATE_TYPED_VARIABLE, createFlyout, );这里把第二步中customCREATE_TYPED_VARIABLE与第三步的createFlyout函数绑定。第五步创建并初始化 Typed Variable Modalconst typedVarModal new TypedVariableModal(workspace, callbackName, [ [PENGUIN, Penguin], [GIRAFFE, Giraffe], ]); typedVarModal.init();构造函数三个参数的含义如下参数类型说明workspaceBlockly.WorkspaceSvg模态框注册到的工作区btnCallbackNamestring第三步按钮callbackKey对应的回调名init()会把它注册到工作区typesArrayArraystring类型列表每个元素是[显示名, 类型名]例如[[Penguin, PENGUIN]]init()的源码实现见 TypedVariableModal.js非常简洁先调用父类super.init()完成模态框 DOM 初始化再调用this.workspace_.registerButtonCallback(this.btnCallBackName_, () this.show())把按钮回调名绑定到show()。也就是说用户点击 Flyout 里的 Create Typed Variable 按钮时模态框即弹出。核心 API 一览README 中公开的实例 API 及其源码对应关系如下方法作用源码位置init()初始化模态框并注册按钮回调TypedVariableModal.jsdispose()销毁模态框并注销按钮回调TypedVariableModal.jsshow()显示模态框并聚焦第一个可聚焦元素关闭按钮继承自Modalhide()隐藏模态框继承自Modalrender()创建模态框全部 DOM 元素内部由renderContent_()/renderFooter_()组成setLocale(messages)替换模态框文案支持多语言TypedVariableModal.js几个值得注意的实现细节dispose()除了调用super.dispose()释放父类资源外还会调用workspace_.removeButtonCallback(this.btnCallBackName_)注销按钮回调避免工作区残留悬挂引用。show()后焦点落在关闭按钮blocklyModalBtn blocklyModalBtnClose最后可聚焦元素是确认/取消按钮——这是Modal基类内置的焦点圈定逻辑单测 typed_variable_modal_test.mocha.js 对此做了断言。构造函数将this.shouldCloseOnOverlayClick false置为false源码 L101即点击遮罩层不会关闭模态框只能通过右上角X或Esc键关闭防止用户误触丢失输入内容。输入校验与重名冲突处理源码级原理用户点击 Ok 确认后onConfirm_()源码 L170-L200依次执行三段逻辑名称合法性校验getValidInput_()先取输入框值用newVar.replace(/[\s\xa0]/g, ).trim()把连续空白含不间断空格\xa0折叠为单个空格并去除首尾空白如果清洗后的名称恰好等于Blockly.Msg[RENAME_VARIABLE]或Blockly.Msg[NEW_VARIABLE]即重命名变量...、创建变量...等系统占位文案则判定为非法返回null并弹出TYPED_VAR_MODAL_INVALID_NAME提示。跨类型重名检查调用Blockly.Variables.nameUsedWithAnyType(text, workspace)做不区分大小写的全变量名搜索。该函数定义于 packages/blockly/core/variables.ts遍历变量表把所有名称toLowerCase()后比对返回第一个同名变量。分支处理若同名变量类型相同弹出VARIABLE_ALREADY_EXISTSA variable named %1 already exists.若同名变量类型不同弹出VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPEA variable named %1 already exists for another type: %2.其中%2由getDisplayName_()根据[显示名, 类型名]配对反查得到无冲突调用workspace.getVariableMap().createVariable(text, type)真正创建类型化变量并hide()关闭模态框。单测 typed_variable_modal_test.mocha.js 用 sinon stub 覆盖了空名称合法名称同类型已存在不同类型已存在四条路径可作为理解该逻辑的参考。类型列表types详解types参数是ArrayArraystring每个子数组形如[displayName, typeName]displayName索引 0是展示给用户的类型名称显示在单选按钮旁边的label中typeName索引 1是写入变量模型的真实类型标识同时用作单选按钮的id即selectedType_的值。源码createVariableTypeContainer_()L314-L340会为每个类型生成一个li内含typeradio、nameblocklyVariableType的单选按钮及for指向该 id 的label点击任一选项时selectedType_被更新为该选项的 id。模态框每次打开时resetModalInputs_()会自动勾选第一个类型并清空变量名输入框保证干净的输入状态。由于单选按钮 id 直接使用类型名建议类型名保持唯一且不含空格等特殊字符避免 HTML id 冲突。国际化与消息定制插件目前不提供内置的多语言翻译但 README 明确说明可通过typedVarModal.setLocale(messages)传入翻译后的消息对象来实现多语言支持。setLocale()的实现是把每个 key 直接写入全局的Blockly.Msg源码 L132-L136因此后续渲染的按钮、标签、标题都会使用新文案构造函数内部也有一份英文默认值并通过Object.assign(messages, optMessages)合并用户传入的第四参optMessages。需要翻译的 6 个消息 key 及默认值如下Key默认值英文用途TYPED_VAR_MODAL_CONFIRM_BUTTONOk确认按钮文字TYPED_VAR_MODAL_VARIABLE_NAME_LABELVariable Name:变量名输入框前的标签TYPED_VAR_MODAL_TYPES_LABELVariable Types类型区块的标题TYPED_VAR_MODAL_CANCEL_BUTTONCancel取消按钮文字TYPED_VAR_MODAL_TITLECreate Typed Variable模态框标题TYPED_VAR_MODAL_INVALID_NAMEName is not valid. Please choose a different name.非法名称提示名称等于重命名/新建变量的系统文案、或为空字符串时触发例如切换到中文typedVarModal.setLocale({ TYPED_VAR_MODAL_CONFIRM_BUTTON: 确定, TYPED_VAR_MODAL_CANCEL_BUTTON: 取消, TYPED_VAR_MODAL_TITLE: 创建类型化变量, TYPED_VAR_MODAL_VARIABLE_NAME_LABEL: 变量名称, TYPED_VAR_MODAL_TYPES_LABEL: 变量类型, TYPED_VAR_MODAL_INVALID_NAME: 名称无效请选择其他名称。, });单测 typed_variable_modal_test.mocha.js 验证了setLocale()会正确写入Blockly.Msg。样式与 DOM 结构插件通过Blockly.Css.register(...)在导入时注入内置样式源码 L370-L391因此无需额外引入 CSS 文件。关键样式类包括.typedModalTitle模态框标题加粗.typedModalVariableInputContainer/.typedModalVariableLabel/.typedModalVariableNameInput变量名输入区.typedModalTypes类型区块使用display: flex; flex-wrap: wrap让类型单选列表横向换行排列.typedModalList li每个类型项margin-right: 1em分隔。DOM 结构由renderContent_()变量名输入区 类型列表与renderFooter_()确认 取消两个按钮分别带blocklyModalBtn blocklyModalBtnPrimary与blocklyModalBtn类构成单测 render 套件 断言了这些节点与按钮数量。本地开发与测试仓库内提供了完整的测试与演示环境测试入口test/typed_variable_modal_test.mocha.js 使用 mocha jsdom sinon覆盖init、show焦点、setLocale、onConfirm_四分支、getDisplayName_、getValidInput_、render、按钮与容器创建等全部核心逻辑演示页面test/index.js 通过blockly/dev-tools的createPlayground搭建交互 playground并把Typed Variables自定义分类注入toolboxCategories运行npm test内部调用blockly-scripts test见 package.json即可构建并打开 test/index.html 实际操作。许可证本插件采用 Apache 2.0 许可证见 README 与源码文件头SPDX-License-Identifier: Apache-2.0可自由用于商业与开源项目。【免费下载链接】blocklyThe web-based visual programming editor.项目地址: https://gitcode.com/gh_mirrors/bl/blockly创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考