fix: 解决编辑器的问题

This commit is contained in:
奔跑的面条 2022-07-06 14:13:27 +08:00
parent 8d0615bc95
commit 6da5c613de
7 changed files with 160 additions and 109 deletions

View File

@ -1,4 +1,7 @@
export const OUTPUT_DIR = 'dist'; export const OUTPUT_DIR = 'dist'
// monaco-editor 路径
export const prefix = `monaco-editor/esm/vs`
// chunk 警告大小 // chunk 警告大小
export const chunkSizeWarningLimit = 2000 export const chunkSizeWarningLimit = 2000
@ -11,7 +14,14 @@ export const rollupOptions = {
output: { output: {
chunkFileNames: 'static/js/[name]-[hash].js', chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js', entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]' assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks: {
jsonWorker: [`${prefix}/language/json/json.worker`],
cssWorker: [`${prefix}/language/css/css.worker`],
htmlWorker: [`${prefix}/language/html/html.worker`],
tsWorker: [`${prefix}/language/typescript/ts.worker`],
editorWorker: [`${prefix}/editor/editor.worker`]
}
} }
} }
@ -22,4 +32,4 @@ export const terserOptions = {
drop_console: true, drop_console: true,
drop_debugger: true drop_debugger: true
} }
} }

View File

@ -64,6 +64,7 @@
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5", "vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6", "vite-plugin-mock": "^2.9.6",
"vite-plugin-monaco-editor": "^1.1.0",
"vue-echarts": "^6.0.2", "vue-echarts": "^6.0.2",
"vue-tsc": "^0.28.10" "vue-tsc": "^0.28.10"
} }

View File

@ -47,6 +47,7 @@ specifiers:
vite-plugin-compression: ^0.5.1 vite-plugin-compression: ^0.5.1
vite-plugin-importer: ^0.2.5 vite-plugin-importer: ^0.2.5
vite-plugin-mock: ^2.9.6 vite-plugin-mock: ^2.9.6
vite-plugin-monaco-editor: ^1.1.0
vue: ^3.2.31 vue: ^3.2.31
vue-demi: ^0.13.1 vue-demi: ^0.13.1
vue-echarts: ^6.0.2 vue-echarts: ^6.0.2
@ -113,6 +114,7 @@ devDependencies:
vite-plugin-compression: 0.5.1_vite@2.9.5 vite-plugin-compression: 0.5.1_vite@2.9.5
vite-plugin-importer: 0.2.5 vite-plugin-importer: 0.2.5
vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.9.5 vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.9.5
vite-plugin-monaco-editor: 1.1.0_monaco-editor@0.33.0
vue-echarts: 6.0.3_echarts@5.3.3+vue@3.2.37 vue-echarts: 6.0.3_echarts@5.3.3+vue@3.2.37
vue-tsc: 0.28.10_typescript@4.7.3 vue-tsc: 0.28.10_typescript@4.7.3
@ -5111,6 +5113,14 @@ packages:
- supports-color - supports-color
dev: true dev: true
/vite-plugin-monaco-editor/1.1.0_monaco-editor@0.33.0:
resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==}
peerDependencies:
monaco-editor: '>=0.33.0'
dependencies:
monaco-editor: 0.33.0
dev: true
/vite/2.9.5_sass@1.52.3: /vite/2.9.5_sass@1.52.3:
resolution: {integrity: sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==} resolution: {integrity: sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==}
engines: {node: '>=12.2.0'} engines: {node: '>=12.2.0'}

View File

@ -1,46 +1,83 @@
import { ref, onBeforeUnmount, nextTick } from 'vue'
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js' import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
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'
export const useMonacoEditor = (language = 'json') => { export const useMonacoEditor = (language = 'javascript') => {
let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
let initReadOnly = false let initReadOnly = false
const updateVal = async (val: string) => { const el = ref<HTMLElement | null>(null)
monacoEditor?.setValue(val)
setTimeout(async () => { // @ts-ignore
initReadOnly && monacoEditor?.updateOptions({ readOnly: false }) self.MonacoEnvironment = {
// await monacoEditor?.getAction('editor.action.formatDocument')?.run() getWorker(_: any, label: string) {
initReadOnly && monacoEditor?.updateOptions({ readOnly: true }) if (label === 'json') {
}, 100) 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()
}
} }
const createEditor = ( // 格式化
el: HTMLElement | null, const onFormatDoc = async () => {
editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {} await monacoEditor?.getAction('monacoEditor.action.formatDocument')?.run()
) => { }
if (monacoEditor) {
return // 更新
} const updateVal = (val: string) => {
nextTick(async () => {
monacoEditor?.setValue(val)
initReadOnly && monacoEditor?.updateOptions({ readOnly: false })
await onFormatDoc()
initReadOnly && monacoEditor?.updateOptions({ readOnly: true })
})
}
// 创建实例
const createEditor = (editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}) => {
if (!el.value) return
const javascriptModel = monaco.editor.createModel('', language)
initReadOnly = !!editorOption.readOnly initReadOnly = !!editorOption.readOnly
monacoEditor = // 创建
el && monacoEditor = monaco.editor.create(el.value, {
monaco.editor.create(el, { model: javascriptModel,
language, minimap: { enabled: true },
minimap: { enabled: false }, roundedSelection: false,
theme: 'vs-dark', theme: 'vs-dark',
multiCursorModifier: 'ctrlCmd', multiCursorModifier: 'ctrlCmd',
scrollbar: { scrollbar: {
verticalScrollbarSize: 8, verticalScrollbarSize: 8,
horizontalScrollbarSize: 8 horizontalScrollbarSize: 8
}, },
tabSize: 2, tabSize: 2,
automaticLayout: true, // 自适应宽高 fontSize: 16, //字体大小
...editorOption autoIndent: 'advanced', //自动布局
}) automaticLayout: true, // 自适应宽高
...editorOption
})
return monacoEditor return monacoEditor
} }
const onFormatDoc = () => {
monacoEditor?.getAction('editor.action.formatDocument').run() // 卸载
} onBeforeUnmount(() => {
if (monacoEditor) monacoEditor.dispose()
})
return { return {
el,
updateVal, updateVal,
getEditor: () => monacoEditor, getEditor: () => monacoEditor,
createEditor, createEditor,

View File

@ -1,75 +1,65 @@
<template> <template>
<div class="editor-area" :style="{ width, height }"> <div ref="el" class="editor-area" :style="{ width, height }"></div>
</div>
</template> </template>
<script lang='ts'> <script lang="ts" setup>
import { defineComponent, ref } from 'vue' import { onMounted, watch, PropType } from 'vue'
import { useMonacoEditor } from './index.hook' import { useMonacoEditor } from './index.hook'
export default defineComponent({ const props = defineProps({
props: { width: {
width: { type: String as PropType<string>,
type: String, default: '100%'
default: '100%'
},
height: {
type: String,
default: '90vh'
},
language: {
type: String,
default: 'json'
},
preComment: {
type: String,
default: ''
},
modelValue: {
type: String,
default: ''
},
editorOptions: {
type: Object,
default: () => ({})
},
}, },
watch: { height: {
modelValue(val) { type: String as PropType<string>,
val !== this.getEditor()?.getValue() && this.updateMonacoVal(val) default: '90vh'
}
}, },
setup(props) { language: {
const { updateVal, getEditor, createEditor, onFormatDoc } = useMonacoEditor(props.language) type: String as PropType<string>,
const isFull = ref(false) default: 'javascript'
return {
isFull,
updateVal,
getEditor,
createEditor,
onFormatDoc
}
}, },
methods: { preComment: {
updateMonacoVal(_val?: string) { type: String as PropType<string>,
const { modelValue, preComment } = this.$props default: ''
const val = preComment ? `${preComment}\n${_val || modelValue}` : (_val || modelValue)
this.updateVal(val)
}
}, },
mounted() { modelValue: {
if (this.$el) { type: String as PropType<string>,
const monacoEditor = this.createEditor(this.$el, this.$props.editorOptions) default: ''
this.updateMonacoVal() },
monacoEditor!.onDidChangeModelContent(() => { editorOptions: {
this.$emit('update:modelValue', monacoEditor!.getValue()) type: Object as PropType<object>,
}) default: () => ({})
monacoEditor!.onDidBlurEditorText(() => {
this.$emit('blur')
})
}
} }
}) })
const emits = defineEmits(['blur', 'update:modelValue'])
const { el, updateVal, getEditor, createEditor } = useMonacoEditor(props.language)
const updateMonacoVal = (_val?: string) => {
const { modelValue, preComment } = props
const val = preComment ? `${preComment}\n${_val || modelValue}` : _val || modelValue
updateVal(val)
}
onMounted(() => {
const monacoEditor = createEditor(props.editorOptions)
monacoEditor!.onDidChangeModelContent(() => {
emits('update:modelValue', monacoEditor!.getValue())
})
monacoEditor!.onDidBlurEditorText(() => {
emits('blur')
})
updateMonacoVal()
})
watch(
() => props.modelValue,
(val: string) => {
val !== getEditor()?.getValue() && updateMonacoVal(val)
}
)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -81,4 +71,4 @@ export default defineComponent({
padding-left: 0; padding-left: 0;
box-sizing: border-box; box-sizing: border-box;
} }
</style> </style>

View File

@ -56,9 +56,11 @@
<div> <div>
<n-space vertical> <n-space vertical>
<n-text depth="3">// => data </n-text> <n-text depth="3">// => data </n-text>
<p><span class="func-keyword">function</span>&nbsp;&nbsp;filter(data)&nbsp;&nbsp;{</p> <n-tag type="info">
<monaco-editor width="460px" height="380px" v-model:modelValue="filter" language="json" /> <span class="func-keyword">function</span>&nbsp;&nbsp;filter(data)&nbsp;&nbsp;{
<p>}</p> </n-tag>
<monaco-editor v-model:modelValue="filter" width="460px" height="380px" language="javascript" />
<n-tag type="info">}</n-tag>
</n-space> </n-space>
</div> </div>
<n-divider vertical style="height: 480px" /> <n-divider vertical style="height: 480px" />
@ -171,9 +173,6 @@ const saveFilter = () => {
targetData.value.filter = filter.value targetData.value.filter = filter.value
closeFilter() closeFilter()
} }
//
const filterData = (data: any) => {}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -3,7 +3,8 @@ import vue from '@vitejs/plugin-vue'
import { resolve } from 'path' import { resolve } from 'path'
import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant' import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant'
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
import { viteMockServe} from "vite-plugin-mock"; import { viteMockServe } from 'vite-plugin-mock'
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
function pathResolve(dir: string) { function pathResolve(dir: string) {
return resolve(process.cwd(), '.', dir) return resolve(process.cwd(), '.', dir)
@ -36,17 +37,20 @@ export default defineConfig({
}, },
plugins: [ plugins: [
vue(), vue(),
monacoEditorPlugin({
languageWorkers: ['editorWorkerService', 'typescript', 'json']
}),
viteMockServe({ viteMockServe({
mockPath: "/src/api/mock", mockPath: '/src/api/mock',
// 开发打包开关 // 开发打包开关
localEnabled: true, localEnabled: true,
// 生产打包开关 // 生产打包开关
prodEnabled: true, prodEnabled: true,
// 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件 // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
supportTs: true, supportTs: true,
// 监视文件更改 // 监视文件更改
watchFiles: true, watchFiles: true
}), }),
// 压缩 // 压缩
viteCompression({ viteCompression({
verbose: true, verbose: true,