vue3+vite 使用esm方式引入monaco-editor
monaco-editor是微软的项目,但使用npm包方式,文件太大,导致项目会卡顿,所以使用了esm方式,话不多说直接上代码。
·
monaco-editor是微软的项目,但使用npm包方式,文件太大,导致项目会卡顿,所以使用了esm方式,话不多说直接上代码
<template>
<div ref="codeEditBox" class="code-edit-container"> </div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, onBeforeUnmount, watch } from 'vue'
import { editorProps } from './monacoEditorType/index'
export default defineComponent({
name: 'MonacoEditor',
props: editorProps,
emits: ['update:modelValue', 'change', 'editor-mounted'],
setup(props, { emit }) {
let editor: any
const codeEditBox = ref()
let monacoInited = false
const loadScriptResultMap = {}
// Script引入地址方法
const importScript = src => {
if (loadScriptResultMap[src]) {
return loadScriptResultMap[src]
}
loadScriptResultMap[src] = new Promise((resolve, reject) => {
const newScript = document.createElement('script')
newScript.src = src
document.body.append(newScript)
newScript.addEventListener('load', () => {
resolve(true)
})
newScript.onerror = () => {
monacoInited = false
document.body.removeChild(newScript)
reject()
}
})
return loadScriptResultMap[src]
}
// 引入monaco-editor
const importMonaco = () => {
if (monacoInited === true) {
return Promise.resolve()
}
return importScript('https://g.alicdn.com/code/lib/monaco-editor/0.34.1/min/vs/loader.js')
.then(() => {
window.require.config({ paths: { vs: '//g.alicdn.com/code/lib/monaco-editor/0.34.1/min/vs' } })
monacoInited = true
})
.catch(() => {
monacoInited = false
})
}
// 添加编辑器worker
;(self as any).MonacoEnvironment = {
getWorkerUrl: function (workerId, label) {
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
self.MonacoEnvironment = {
baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/'
};
importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/base/worker/workerMain.js');`)}`
},
}
// 初始化编辑器
const initMonaco = () => {
importMonaco().then(() => {
window.require(['vs/editor/editor.main'], () => {
if (codeEditBox.value) {
editor = window.monaco.editor.create(codeEditBox.value, {
value: props.modelValue,
language: props.language,
theme: props.theme,
...props.options,
})
window.monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
})
window.monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: window.monaco.languages.typescript.ScriptTarget.ES2020,
allowNonTsExtensions: true,
})
// 监听值的变化
editor.onDidChangeModelContent(() => {
const value = editor.getValue() // 给父组件实时返回最新文本
emit('update:modelValue', value)
emit('change', value)
})
emit('editor-mounted', editor)
}
})
})
}
onBeforeUnmount(() => {
editor.dispose() // 销毁编辑器
})
onMounted(() => {
initMonaco()
})
watch(
() => props.modelValue,
newValue => {
if (editor) {
const value = editor.getValue()
if (newValue !== value) {
editor.setValue(newValue)
}
}
}
)
watch(
() => props.options,
newValue => {
editor.updateOptions(newValue)
},
{ deep: true }
)
watch(
() => props.readOnly,
() => {
editor.updateOptions({ readOnly: props.readOnly })
},
{ deep: true }
)
watch(
() => props.language,
newValue => {
window.monaco.editor.setModelLanguage(editor.getModel()!, newValue)
}
)
return {
codeEditBox,
}
},
})
</script>
<style scoped lang="scss">
.code-edit-container {
width: 100%;
flex: 1;
height: 100%;
overflow-y: auto;
}
</style>
monacoEditorType文件
import { PropType } from 'vue'
export type Theme = 'vs' | 'hc-black' | 'vs-dark'
export type FoldingStrategy = 'auto' | 'indentation'
export type RenderLineHighlight = 'all' | 'line' | 'none' | 'gutter' // 行亮
export interface Options {
automaticLayout: boolean // 自适应布局
foldingStrategy: FoldingStrategy // 折叠方式 auto | indentation
renderLineHighlight: RenderLineHighlight // 行亮
selectOnLineNumbers: boolean // 显示行号
placeholder: string
minimap: {
// 关闭小地图
enabled: boolean
}
// readOnly: Boolean // 只读
fontSize: number // 字体大小
scrollBeyondLastLine: boolean // 取消代码后面一大段空白
overviewRulerBorder: boolean // 不要滚动条的边框
}
export const editorProps = {
modelValue: {
type: String as PropType<string>,
default: null,
},
width: {
type: [String, Number] as PropType<string | number>,
default: '100%',
},
height: {
type: [String, Number] as PropType<string | number>,
default: '100%',
},
language: {
type: String as PropType<string>,
default: 'javascript',
},
readOnly: {
type: Boolean,
default: false,
},
theme: {
type: String as PropType<Theme>,
validator(value: string): boolean {
return ['vs', 'hc-black', 'vs-dark', 'hc-light'].includes(value)
},
default: 'vs-dark',
},
options: {
type: Object as PropType<Options>,
default() {
return {
automaticLayout: true,
foldingStrategy: 'indentation', // 折叠方式 auto | indentation
renderLineHighlight: 'all', // 行亮
selectOnLineNumbers: true, // 显示行号
minimap: {
// 关闭小地图
enabled: true,
},
placeholder: 'please enter...',
// readOnly: false, // 只读
fontSize: 16, // 字体大小
scrollBeyondLastLine: false, // 取消代码后面一大段空白
overviewRulerBorder: false, // 不要滚动条的边框
}
},
},
}
在父组件中使用
<template>
<MonacoEditor v-model="value" :language="codeLanguage" width="100%" height="100%" @editor-mounted="editorMounted" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import MonacoEditor from '@/components/MonacoEditor/index.vue'
const value = ref('let a = 234') // 编辑器代码显示的值
const codeLanguage = ref('javascript') // 要加载的语言类型
// 加载完成操作
const editorMounted = (editor: any) => {
console.log('editor实例加载完成', editor)
}
</script>
更多推荐
已为社区贡献1条内容
所有评论(0)