amis Editor 代码编辑器组件详解:基于 Monaco 的多语言高亮、事件与动作完全实践指南
2026/9/13 13:30:30 网站建设 项目流程

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放入formbody中,通过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 常量 完全一致):

batccoffeescriptcppcsharpcssdockerfilefsharpgohandlebarshtmlinijavajavascriptjsonlessluamarkdownmsdaxobjective-cphpplaintextpostiatspowershellpugpythonrrazorrubysbscssshellsolsqlswifttypescriptvbxmlyaml

{ "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-editorpython-editor等类型与editor + language的效果等价。此外还额外注册了 js-editor 与 ts-editor 两个别名类型。

language支持通过${xxx}变量取值。源码中 render 方法 会先判断language是否为纯变量(isPureVariable),如果是则从当前数据中解析出真实语言,便于根据外部数据动态选择高亮模式(首次渲染时生效)。

值得一提的是,当languagejson时,初始化阶段会自动开启 monaco 的 JSON 诊断校验(validate: trueallowComments: 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: trueformatOnType: trueformatOnPaste: truebracketPairColorization.enabled: true(括号对彩色高亮)、scrollbar.alwaysConsumeMouseWheel: false等。用户配置的options展开在最外层,可覆盖上述任何默认项。

编辑器自定义开发(editorDidMount)

如果想进行深度定制,比如实现自动完成功能,可以通过自定义editorDidMount属性获取 monaco 实例。该属性支持两种写法:

  1. 在 JS 中直接写函数;
  2. 写一个字符串,源码会将其包装为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 全局命名空间,可访问languageseditorKeyMod等全部 API;
  • 若回调返回一个函数,该函数会在编辑器组件卸载时被调用,用于清理资源(如注销补全提供器、事件监听)。源码实现见 handleEditorMounted:返回的dispose被推入toDispose数组,随componentWillUnmount统一执行,避免语言提供器泄漏。

从源码结构看,底层 UI 组件还提供了editorWillMount(monaco)(编辑器创建前,可修改 monaco 全局配置)与editorWillUnmount(editor, monaco)(实例销毁前)两个更底层的钩子(见 EditorBaseProps),表单层目前对外暴露的是editorDidMount

属性表

除了支持 普通表单项属性表 中的配置(namelabelvaluedisabledvisible等)以外,editor 还支持以下专属配置:

属性名类型默认值说明
languagestringjavascript编辑器高亮的语言,支持通过${xxx}变量获取
sizestringmd编辑器高度,取值可以是mdlgxlxxl(源码样式中还额外支持sm
allowFullscreenbooleanfalse是否显示全屏模式开关
optionsobject见上文默认配置monaco 编辑器的其它配置,比如是否显示行号等,可参考 monaco 官方IEditorOptions文档,不过无法设置readOnly,只读模式需要使用disabled: true
placeholderstring-占位描述,没有值的时候展示

关于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拦截:若事件被阻止,则不会继续执行onChangeonFocus/onBlur回调,可用于校验场景下禁止值更新。

动作表

当前组件对外暴露以下特性动作,其他组件可以通过指定actionType: 动作名称componentId: 该组件id来触发这些动作,动作配置可以通过args: {动作配置项名称: xxx}来配置具体的参数,详细请查看事件动作。

动作名称动作配置说明
clear-清空
reset-将值重置为初始值。6.3.0 及以下版本为resetValue
focus-获取焦点
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包裹成一次独立的撤销步骤——这意味着外部赋值后按一次Ctrl+Z即可整体回退,而不会逐字符撤销;同时置位preventTriggerChangeEvent标志位,避免程序化赋值反向触发onChange,防止表单数据循环更新。若语言为json,外部传入的值还会先经JSON.parse再序列化为两空格缩进格式后写入。

另一个工程细节是 monaco 的 Web Worker 配置:amis-ui 在模块加载时初始化window.MonacoEnvironment.getWorkerUrl,按语言标签(json/css/html/typescript/javascript)映射到json.worker.jscss.worker.jshtml.worker.jsts.worker.js等 worker 地址;如果地址是 http(s) 开头,则包装为data:协议的内联importScripts形式加载,保证在 SDK 部署路径不可预知的场景下 worker 也能正常启动。

小结

amis 的editor组件以极薄的 JSON 配置面覆盖了三类典型需求:

  1. 常规代码输入type: editor(或xxx-editor简写)+language即可获得带高亮、折叠、括号配色的代码输入框,JSON 类型还自带诊断校验;
  2. 展示与只读disabled: true+size档位 +options透传 monaco 选项,满足"只读代码块"展示;
  3. 深度定制与联动editorDidMount暴露 monaco 实例用于注册补全、校验等能力,配合onEvent(change/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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询