diff --git a/mock/role/index.mock.ts b/mock/role/index.mock.ts index 1e33d93..7aae345 100644 --- a/mock/role/index.mock.ts +++ b/mock/role/index.mock.ts @@ -202,6 +202,14 @@ const adminList = [ meta: { title: 'router.jsonEditor' } + }, + { + path: 'code-editor', + component: 'views/Components/Editor/CodeEditor', + name: 'CodeEditor', + meta: { + title: 'router.codeEditor' + } } ] }, @@ -687,6 +695,7 @@ const testList: string[] = [ '/components/editor-demo', '/components/editor-demo/editor', '/components/editor-demo/json-editor', + '/components/editor-demo/code-editor', '/components/search', '/components/descriptions', '/components/image-viewer', diff --git a/package.json b/package.json index abe63e6..689ee9f 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,8 @@ "vue-json-pretty": "^2.4.0", "vue-router": "^4.3.0", "vue-types": "^5.1.1", - "xgplayer": "^3.0.14" + "xgplayer": "^3.0.14", + "monaco-editor": "^0.48.0" }, "devDependencies": { "@commitlint/cli": "^19.2.1", diff --git a/src/components/CodeEditor/index.ts b/src/components/CodeEditor/index.ts new file mode 100644 index 0000000..5bf3e9e --- /dev/null +++ b/src/components/CodeEditor/index.ts @@ -0,0 +1,3 @@ +import CodeEditor from './src/CodeEditor.vue' + +export { CodeEditor } diff --git a/src/components/CodeEditor/src/CodeEditor.vue b/src/components/CodeEditor/src/CodeEditor.vue new file mode 100644 index 0000000..306db13 --- /dev/null +++ b/src/components/CodeEditor/src/CodeEditor.vue @@ -0,0 +1,119 @@ + + + diff --git a/src/components/CodeEditor/src/config/config.ts b/src/components/CodeEditor/src/config/config.ts new file mode 100644 index 0000000..4fa7b30 --- /dev/null +++ b/src/components/CodeEditor/src/config/config.ts @@ -0,0 +1,129 @@ +export const languageOptions = [ + { label: 'plaintext', value: 'plaintext' }, + { label: 'abap', value: 'abap' }, + { label: 'apex', value: 'apex' }, + { label: 'azcli', value: 'azcli' }, + { label: 'bat', value: 'bat' }, + { label: 'bicep', value: 'bicep' }, + { label: 'cameligo', value: 'cameligo' }, + { label: 'clojure', value: 'clojure' }, + { label: 'coffeescript', value: 'coffeescript' }, + { label: 'c', value: 'c' }, + { label: 'cpp', value: 'cpp' }, + { label: 'csharp', value: 'csharp' }, + { label: 'csp', value: 'csp' }, + { label: 'css', value: 'css' }, + { label: 'cypher', value: 'cypher' }, + { label: 'dart', value: 'dart' }, + { label: 'dockerfile', value: 'dockerfile' }, + { label: 'ecl', value: 'ecl' }, + { label: 'elixir', value: 'elixir' }, + { label: 'flow9', value: 'flow9' }, + { label: 'fsharp', value: 'fsharp' }, + { label: 'freemarker2', value: 'freemarker2' }, + { + label: 'freemarker2.tag-angle.interpolation-dollar', + value: 'freemarker2.tag-angle.interpolation-dollar' + }, + { + label: 'freemarker2.tag-bracket.interpolation-dollar', + value: 'freemarker2.tag-bracket.interpolation-dollar' + }, + { + label: 'freemarker2.tag-angle.interpolation-bracket', + value: 'freemarker2.tag-angle.interpolation-bracket' + }, + { + label: 'freemarker2.tag-bracket.interpolation-bracket', + value: 'freemarker2.tag-bracket.interpolation-bracket' + }, + { + label: 'freemarker2.tag-auto.interpolation-dollar', + value: 'freemarker2.tag-auto.interpolation-dollar' + }, + { + label: 'freemarker2.tag-auto.interpolation-bracket', + value: 'freemarker2.tag-auto.interpolation-bracket' + }, + { label: 'go', value: 'go' }, + { label: 'graphql', value: 'graphql' }, + { label: 'handlebars', value: 'handlebars' }, + { label: 'hcl', value: 'hcl' }, + { label: 'html', value: 'html' }, + { label: 'ini', value: 'ini' }, + { label: 'java', value: 'java' }, + { label: 'javascript', value: 'javascript' }, + { label: 'julia', value: 'julia' }, + { label: 'kotlin', value: 'kotlin' }, + { label: 'less', value: 'less' }, + { label: 'lexon', value: 'lexon' }, + { label: 'lua', value: 'lua' }, + { label: 'liquid', value: 'liquid' }, + { label: 'm3', value: 'm3' }, + { label: 'markdown', value: 'markdown' }, + { label: 'mdx', value: 'mdx' }, + { label: 'mips', value: 'mips' }, + { label: 'msdax', value: 'msdax' }, + { label: 'mysql', value: 'mysql' }, + { label: 'objective-c', value: 'objective-c' }, + { label: 'pascal', value: 'pascal' }, + { label: 'pascaligo', value: 'pascaligo' }, + { label: 'perl', value: 'perl' }, + { label: 'pgsql', value: 'pgsql' }, + { label: 'php', value: 'php' }, + { label: 'pla', value: 'pla' }, + { label: 'postiats', value: 'postiats' }, + { label: 'powerquery', value: 'powerquery' }, + { label: 'powershell', value: 'powershell' }, + { label: 'proto', value: 'proto' }, + { label: 'pug', value: 'pug' }, + { label: 'python', value: 'python' }, + { label: 'qsharp', value: 'qsharp' }, + { label: 'r', value: 'r' }, + { label: 'razor', value: 'razor' }, + { label: 'redis', value: 'redis' }, + { label: 'redshift', value: 'redshift' }, + { label: 'restructuredtext', value: 'restructuredtext' }, + { label: 'ruby', value: 'ruby' }, + { label: 'rust', value: 'rust' }, + { label: 'sb', value: 'sb' }, + { label: 'scala', value: 'scala' }, + { label: 'scheme', value: 'scheme' }, + { label: 'scss', value: 'scss' }, + { label: 'shell', value: 'shell' }, + { label: 'sol', value: 'sol' }, + { label: 'aes', value: 'aes' }, + { label: 'sparql', value: 'sparql' }, + { label: 'sql', value: 'sql' }, + { label: 'st', value: 'st' }, + { label: 'swift', value: 'swift' }, + { label: 'systemverilog', value: 'systemverilog' }, + { label: 'verilog', value: 'verilog' }, + { label: 'tcl', value: 'tcl' }, + { label: 'twig', value: 'twig' }, + { label: 'typescript', value: 'typescript' }, + { label: 'vb', value: 'vb' }, + { label: 'wgsl', value: 'wgsl' }, + { label: 'xml', value: 'xml' }, + { label: 'yaml', value: 'yaml' }, + { label: 'json', value: 'json' } +] + +export const themeOptions = [ + { + label: 'vs', + value: 'vs' + }, + { + label: 'vs-dark', + value: 'vs-dark' + }, + { + label: 'hc-black', + value: 'hc-black' + }, + { + label: 'hc-light', + value: 'hc-light' + } +] diff --git a/src/hooks/web/useMonacoEditor.ts b/src/hooks/web/useMonacoEditor.ts new file mode 100644 index 0000000..ab464ea --- /dev/null +++ b/src/hooks/web/useMonacoEditor.ts @@ -0,0 +1,129 @@ +import * as monaco from 'monaco-editor' +import { ref, nextTick, onBeforeUnmount } from 'vue' +import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker' +import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker' +import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker' +import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker' +import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker' + +self.MonacoEnvironment = { + getWorker(_, label) { + if (label === 'json') { + return new jsonWorker() + } + if (label === 'css' || label === 'scss' || label === 'less') { + return new cssWorker() + } + if (label === 'html' || label === 'handlebars' || label === 'razor') { + return new htmlWorker() + } + if (label === 'typescript' || label === 'javascript') { + return new tsWorker() + } + return new editorWorker() + } +} + +export function useMonacoEditor(language: string = 'javascript') { + // 编辑器示例 + let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null + // 目标元素 + const monacoEditorRef = ref() + + // 创建实例 + function createEditor(editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}) { + if (!monacoEditorRef.value) return + monacoEditor = monaco.editor.create(monacoEditorRef.value, { + // 初始模型 + model: monaco.editor.createModel('', language), + // 是否启用预览图 + minimap: { enabled: true }, + // 圆角 + roundedSelection: true, + // 主题 + theme: 'vs-dark', + // 主键 + multiCursorModifier: 'ctrlCmd', + // 滚动条 + scrollbar: { + verticalScrollbarSize: 8, + horizontalScrollbarSize: 8 + }, + // 行号 + lineNumbers: 'on', + // tab大小 + tabSize: 2, + //字体大小 + fontSize: 14, + // 控制编辑器在用户键入、粘贴、移动或缩进行时是否应自动调整缩进 + autoIndent: 'advanced', + // 自动布局 + automaticLayout: true, + ...editorOption + }) + return monacoEditor + } + + // 格式化 + async function formatDoc() { + await monacoEditor?.getAction('editor.action.formatDocument')?.run() + } + + // 数据更新 + function updateVal(val: string) { + nextTick(() => { + if (getOption(monaco.editor.EditorOption.readOnly)) { + updateOptions({ readOnly: false }) + } + monacoEditor?.setValue(val) + setTimeout(async () => { + await formatDoc() + }, 10) + }) + } + + // 配置更新 + function updateOptions(opt: monaco.editor.IStandaloneEditorConstructionOptions) { + monacoEditor?.updateOptions(opt) + } + + // 获取配置 + function getOption(name: monaco.editor.EditorOption) { + return monacoEditor?.getOption(name) + } + + // 获取实例 + function getEditor() { + return monacoEditor + } + + function changeLanguage(newLanguage: string) { + const model = monacoEditor?.getModel() + if (model) { + monaco.editor.setModelLanguage(model, newLanguage) + } + } + + function changeTheme(newTheme: string) { + monaco.editor.setTheme(newTheme) + } + + // 页面离开 销毁 + onBeforeUnmount(() => { + if (monacoEditor) { + monacoEditor.dispose() + } + }) + + return { + monacoEditorRef, + createEditor, + getEditor, + updateVal, + updateOptions, + getOption, + formatDoc, + changeLanguage, + changeTheme + } +} diff --git a/src/locales/en.ts b/src/locales/en.ts index c68a9d8..f038abf 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -153,6 +153,7 @@ export default { editor: 'Editor', richText: 'Rich text', jsonEditor: 'JSON Editor', + codeEditor: 'Code Editor', dialog: 'Dialog', imageViewer: 'Image viewer', descriptions: 'Descriptions', @@ -473,7 +474,9 @@ export default { richText: 'Rich text', richTextDes: 'Secondary packaging based on wangeditor', jsonEditor: 'JSON Editor', - jsonEditorDes: 'Secondary packaging based on vue-json-pretty' + jsonEditorDes: 'Secondary packaging based on vue-json-pretty', + codeEditor: 'Code Editor', + codeEditorDes: 'Secondary packaging based on monaco-editor' }, dialogDemo: { dialog: 'Dialog', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 7d4cf72..a4df161 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -151,6 +151,7 @@ export default { editor: '编辑器', richText: '富文本', jsonEditor: 'JSON编辑器', + codeEditor: '代码编辑器', dialog: '弹窗', imageViewer: '图片预览', descriptions: '描述', @@ -464,7 +465,9 @@ export default { richText: '富文本', richTextDes: '基于 wangeditor 二次封装', jsonEditor: 'JSON编辑器', - jsonEditorDes: '基于 vue-json-pretty 二次封装' + jsonEditorDes: '基于 vue-json-pretty 二次封装', + codeEditor: '代码编辑器', + codeEditorDes: '基于 monaco-editor 二次封装' }, dialogDemo: { dialog: '弹窗', diff --git a/src/views/Components/Editor/CodeEditor.vue b/src/views/Components/Editor/CodeEditor.vue new file mode 100644 index 0000000..db80bb0 --- /dev/null +++ b/src/views/Components/Editor/CodeEditor.vue @@ -0,0 +1,23 @@ + +