amis Editor 代码编辑器组件详解:基于 Monaco 的多语言高亮、事件与动作完全实践指南
amis Editor 代码编辑器组件详解基于 Monaco 的多语言高亮、事件与动作完全实践指南【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis本文基于 amis 官方文档中的 Editor 编辑器组件说明展开系统讲解该组件在表单中的基本用法、语言高亮配置、只读与全屏模式、monaco 选项控制以及深度定制能力并结合当前仓库中的源码实现amis 表单层渲染器、amis-ui 基础编辑器组件补充其默认配置、高度自适应与资源清理等底层机制。读完本文你可以直接在生产表单中配置出带语法高亮、可全屏、可联动的代码编辑器并掌握通过editorDidMount获取 monaco 实例实现自动补全等高级定制的方法。组件定位amis 的editor是表单中的一个代码编辑表单项底层基于 monaco-editor 开发适合收集脚本片段、配置文本、JSON/SQL 等代码内容。如果业务场景是富文本编辑如公告、文章正文应改用 Rich-Text 组件二者定位不同。从源码结构看该组件分为两层表单层EditorControl 是注册到 amis 表单体系的FormItem负责取值、派发事件change/focus/blur、响应特性动作clear/reset/focus、高度自适应等UI 层amis-ui 的 Editor 组件 封装了 monaco 的加载、初始化、全屏切换与占位符展示表单层通过LazyComponent以懒加载方式引用它避免首屏引入整个 monaco 运行时。基本用法最简配置如下将editor放入form的body中通过name收集提交值{ type: form, api: /api/mock2/form/saveForm, body: [ { type: editor, name: editor, label: 编辑器, placeholder: function() {\n console.log(hello world)\n} } ] }其中placeholder在编辑器没有值时以占位文本形式展示。对应到 UI 层实现Editor 组件的 render 方法 只有在this.editor placeholder !value同时满足时才渲染占位符节点因此占位内容仅在初始空值状态下可见输入后立即消失。支持的语言通过language属性指定语法高亮语言支持的语言列表如下与源码中 availableLanguages 常量 完全一致bat、c、coffeescript、cpp、csharp、css、dockerfile、fsharp、go、handlebars、html、ini、java、javascript、json、less、lua、markdown、msdax、objective-c、php、plaintext、postiats、powershell、pug、python、r、razor、ruby、sb、scss、shell、sol、sql、swift、typescript、vb、xml、yaml{ type: form, api: /api/mock2/form/saveForm, body: [ { type: editor, name: editor, label: JSON编辑器, language: json } ] }因为性能原因上面的例子不支持实时修改language生效——monaco 的语言模式在编辑器创建时绑定运行中切换需要重建编辑器实例。当然你也可以使用xxx-editor这种类型简写形式例如type: json-editor{ type: form, api: /api/mock2/form/saveForm, body: [ { type: json-editor, name: editor, label: JSON编辑器 } ] }从源码看EditorControls 注册逻辑 会遍历availableLanguages数组为每种语言动态生成一个${lang}-editor类型的FormItem渲染器其defaultProps.language固定为对应语言因此json-editor、python-editor等类型与editor language的效果等价。此外还额外注册了 js-editor 与 ts-editor 两个别名类型。language支持通过${xxx}变量取值。源码中 render 方法 会先判断language是否为纯变量isPureVariable如果是则从当前数据中解析出真实语言便于根据外部数据动态选择高亮模式首次渲染时生效。值得一提的是当language为json时初始化阶段会自动开启 monaco 的 JSON 诊断校验validate: true、allowComments: true并对字符串值自动做JSON.parse后重新格式化为两空格缩进使 JSON 编辑器开箱即带语法检查与美化能力。只读模式使用disabled: true让编辑器变为只读{ type: form, api: /api/mock2/form/saveForm, body: [ { type: json-editor, name: editor, disabled: true, label: JSON编辑器 } ] }实现上表单层会将disabled透传为 monaco 的readOnly选项当disabled状态发生变化时UI 层会在 componentDidUpdate 中调用 updateOptions 动态切换无需重建编辑器。注意options中的readOnly字段不应自行设置只读统一由disabled控制。全屏模式设置allowFullscreen属性为true编辑器右上角会显示全屏开关点击后编辑器进入全屏模式{ type: form, api: /api/mock2/form/saveForm, body: [ { type: editor, name: editor, label: 支持全屏模式的编辑器, allowFullscreen: true } ] }源码行为handleFullscreenModeChange 切换isFullscreen状态全屏样式由 SCSS 中的.is-fullscreen规则实现position: fixed占满视口见 _editor.scss退出全屏时会保存并恢复进入全屏前的宽高调用editor.layout()重新布局避免退出后溢出父容器。编辑器展现控制options通过options属性透传 monaco 编辑器的其它配置例如关闭行号{ type: form, api: /api/mock2/form/saveForm, body: [ { type: editor, name: editor, label: 编辑器, options: { lineNumbers: off } } ] }options即 monaco 官方IEditorOptions的透传入口具体可选字段请查阅 monaco 官方文档但不支持通过它设置readOnly只读模式必须使用disabled: true。结合源码可以看到options会与两层内置默认配置合并。表单层 EditorControl.defaultProps 提供默认配置值作用automaticLayouttrue容器尺寸变化时自动重新布局selectOnLineNumberstrue点击行号选中整行scrollBeyondLastLinefalse禁止滚动越过最后一行foldingtrue启用代码折叠minimap.enabledfalse默认关闭小地图UI 层的 monacoFactory 还会再补一层 monaco 级默认值autoIndent: true、formatOnType: true、formatOnPaste: true、bracketPairColorization.enabled: true括号对彩色高亮、scrollbar.alwaysConsumeMouseWheel: false等。用户配置的options展开在最外层可覆盖上述任何默认项。编辑器自定义开发editorDidMount如果想进行深度定制比如实现自动完成功能可以通过自定义editorDidMount属性获取 monaco 实例。该属性支持两种写法在 JS 中直接写函数写一个字符串源码会将其包装为new Function(editor, monaco, ...)执行适配纯 JSON schema 场景。示例{ type: form, api: /api/mock2/form/saveForm, body: [ { type: editor, name: editor, label: 编辑器, language: myLan, editorDidMount: (editor, monaco) { // editor 是 monaco 实例monaco 是全局的名称空间 const dispose monaco.languages.registerCompletionItemProvider(myLan, { /// 其他细节参考 monaco 手册 }); // 如果返回一个函数这个函数会在编辑器组件卸载的时候调用主要用于清理资源 return dispose; } } ] }关键约定回调参数(editor, monaco)中editor是 monaco 编辑器实例monaco是 monaco 全局命名空间可访问languages、editor、KeyMod等全部 API若回调返回一个函数该函数会在编辑器组件卸载时被调用用于清理资源如注销补全提供器、事件监听。源码实现见 handleEditorMounted返回的dispose被推入toDispose数组随componentWillUnmount统一执行避免语言提供器泄漏。从源码结构看底层 UI 组件还提供了editorWillMount(monaco)编辑器创建前可修改 monaco 全局配置与editorWillUnmount(editor, monaco)实例销毁前两个更底层的钩子见 EditorBaseProps表单层目前对外暴露的是editorDidMount。属性表除了支持 普通表单项属性表 中的配置name、label、value、disabled、visible等以外editor 还支持以下专属配置属性名类型默认值说明languagestringjavascript编辑器高亮的语言支持通过${xxx}变量获取sizestringmd编辑器高度取值可以是md、lg、xl、xxl源码样式中还额外支持smallowFullscreenbooleanfalse是否显示全屏模式开关optionsobject见上文默认配置monaco 编辑器的其它配置比如是否显示行号等可参考 monaco 官方IEditorOptions文档不过无法设置readOnly只读模式需要使用disabled: trueplaceholderstring-占位描述没有值的时候展示关于size源码的 样式定义 中各档位对应的最小高度为sm100px、md250px、lg300px、xl400px、xxl500px。编辑器默认无固定最大高度会随内容行数增长——表单层的 updateContainerSize 通过监听onDidChangeModelDecorations覆盖输入与折叠两类变化计算最后一行位置 一行行高动态设置容器高度并调用editor.layout()实现内容多高、编辑器多高的自适应效果。事件表当前组件会对外派发以下事件可以通过onEvent来监听这些事件并通过actions来配置执行的动作在actions中可以通过${事件参数名}或${event.data.[事件参数名]}来获取事件产生的数据详细请查看事件动作。[name]表示当前组件绑定的名称即name属性如果没有配置name属性则通过value取值。事件名称事件参数说明change[name]: string组件的值代码变化时触发focus[name]: string组件的值输入框获取焦点时触发blur[name]: string组件的值输入框失去焦点时触发源码层面三个事件分别由 handleChange / handleFocus / handleBlur 通过dispatchEvent派发且均支持被上层preventDefault拦截若事件被阻止则不会继续执行onChange或onFocus/onBlur回调可用于校验场景下禁止值更新。动作表当前组件对外暴露以下特性动作其他组件可以通过指定actionType: 动作名称、componentId: 该组件id来触发这些动作动作配置可以通过args: {动作配置项名称: xxx}来配置具体的参数详细请查看事件动作。动作名称动作配置说明clear-清空reset-将值重置为初始值。6.3.0 及以下版本为resetValuefocus-获取焦点setValuevalue: string更新的值更新数据动作处理逻辑集中在表单层的 doAction 方法clear直接onChange()reset优先取表单 pristine 值其次取resetValue最后回退为空字符串focus则调用 monaco 的editor.focus()并恢复最近一次光标位置通过getPosition/setPosition实现使程序化聚焦的体验与用户手动点击一致。clear{ type: form, debug: true, body: [ { type: editor, name: editor, label: 编辑器, id: clear_text, value: hello }, { type: button, label: 清空, onEvent: { click: { actions: [ { actionType: clear, componentId: clear_text } ] } } } ] }reset如果配置了resetValue则重置时使用resetValue的值否则使用初始值。{ type: form, debug: true, body: [ { type: editor, id: reset_text, name: editor, label: 编辑器, value: hello }, { type: button, label: 重置, onEvent: { click: { actions: [ { actionType: reset, componentId: reset_text } ] } } } ] }focus{ type: form, debug: true, body: [ { type: editor, id: focus_text, name: editor, label: 编辑器, value: hello }, { type: button, label: 聚焦, onEvent: { click: { actions: [ { actionType: focus, componentId: focus_text } ] } } } ] }setValue{ type: form, debug: true, body: [ { type: editor, id: setvalue_text, name: editor, label: 编辑器, value: hello }, { type: button, label: 赋值, onEvent: { click: { actions: [ { actionType: setValue, componentId: setvalue_text, args: { value: amis go go go! } } ] } } } ] }外部赋值与源码补充说明除动作表中的setValue外表单数据变化如service拉取到数据、表单initFetch也会更新编辑器内容。UI 层的 componentDidUpdate 对外部值变更做了专门处理当props.value与编辑器当前值不一致时通过pushEditOperations整体替换模型内容并用pushUndoStop包裹成一次独立的撤销步骤——这意味着外部赋值后按一次CtrlZ即可整体回退而不会逐字符撤销同时置位preventTriggerChangeEvent标志位避免程序化赋值反向触发onChange防止表单数据循环更新。若语言为json外部传入的值还会先经JSON.parse再序列化为两空格缩进格式后写入。另一个工程细节是 monaco 的 Web Worker 配置amis-ui 在模块加载时初始化window.MonacoEnvironment.getWorkerUrl按语言标签json/css/html/typescript/javascript映射到json.worker.js、css.worker.js、html.worker.js、ts.worker.js等 worker 地址如果地址是 http(s) 开头则包装为data:协议的内联importScripts形式加载保证在 SDK 部署路径不可预知的场景下 worker 也能正常启动。小结amis 的editor组件以极薄的 JSON 配置面覆盖了三类典型需求常规代码输入type: editor或xxx-editor简写language即可获得带高亮、折叠、括号配色的代码输入框JSON 类型还自带诊断校验展示与只读disabled: truesize档位 options透传 monaco 选项满足只读代码块展示深度定制与联动editorDidMount暴露 monaco 实例用于注册补全、校验等能力配合onEventchange/focus/blur与特性动作clear/reset/focus/setValue可完成与其他表单控件的完整联动。实现上所有关键行为只读切换、光标恢复、外部赋值的撤销分组、高度自适应、资源清理均有源码支撑位于 packages/amis/src/renderers/Form/Editor.tsx 与 packages/amis-ui/src/components/Editor.tsx样式与高度档位定义在 packages/amis-ui/scss/components/form/_editor.scss可作为二次开发时的权威参考。【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考