vue3+vite+ts使用monaco-editor編輯器的簡(jiǎn)單步驟
前言
近期要完成一個(gè)代碼編輯器的內(nèi)容,用的vue3.0+ts+vite架構(gòu),學(xué)習(xí)尚淺, 常在插件上遇坑
特此記錄下在monaco-editor的使用
需求:yaml和sql的文件的高亮、補(bǔ)全


實(shí)現(xiàn)
1.安裝
// ^0.34.1 yarn add monaco-editor
2.在vite.config.js中配置(如果不需要ts\js\html就不需要這么做)
// 強(qiáng)制預(yù)構(gòu)建插件包
optimizeDeps: {
include: [
`monaco-editor/esm/vs/language/json/json.worker`,
`monaco-editor/esm/vs/language/css/css.worker`,
`monaco-editor/esm/vs/language/html/html.worker`,
`monaco-editor/esm/vs/language/typescript/ts.worker`,
`monaco-editor/esm/vs/editor/editor.worker`
],
},
3.組件封裝與使用
monacoEditor.vue組件
<template>
<div
ref="codeEditBox"
class="codeEditBox"
:class="hightChange&&'codeEditBox1'"
/>
</template>
<script lang="ts">
import {
defineComponent, onBeforeUnmount, onMounted, ref, watch,
} from 'vue'
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'
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import * as monaco from 'monaco-editor'
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
import { language as yamlLanguage } from 'monaco-editor/esm/vs/basic-languages/yaml/yaml.js';
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
import { editorProps } from './monacoEditorType'
export default defineComponent({
name: 'MonacoEditor',
props: editorProps,
emits: ['update:modelValue', 'change', 'editor-mounted'],
setup(props, { emit }) {
(self as any).MonacoEnvironment = {
getWorker(_: string, label: string) {
if (label === 'json') {
return new JsonWorker()
}
if (['css', 'scss', 'less'].includes(label)) {
return new CssWorker()
}
if (['html', 'handlebars', 'razor'].includes(label)) {
return new HtmlWorker()
}
if (['typescript', 'javascript'].includes(label)) {
return new TsWorker()
}
return new EditorWorker()
},
}
let editor: any
const codeEditBox = ref()
const init = () => {
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: false,
})
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2020,
allowNonTsExtensions: true,
})
monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems() {
const suggestions:any = [];
// 這個(gè)keywords就是sql.js文件中有的
sqlLanguage.keywords.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: item,
});
})
sqlLanguage.operators.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Operator,
insertText: item,
});
})
sqlLanguage.builtinFunctions.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Function,
insertText: item,
});
})
sqlLanguage.builtinVariables.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Variable,
insertText: item,
});
})
return {
// 最后要返回一個(gè)數(shù)組
suggestions,
};
},
})
monaco.languages.registerCompletionItemProvider('yaml', {
provideCompletionItems() {
const suggestions:any = [];
// 這個(gè)keywords就是python.js文件中有的
yamlLanguage.keywords.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: item,
});
})
return {
// 最后要返回一個(gè)數(shù)組
suggestions,
};
},
})
editor = monaco.editor.create(codeEditBox.value, {
value: props.modelValue,
language: props.language,
readOnly: props.readOnly,
theme: props.theme,
...props.options,
})
// 監(jiān)聽(tīng)值的變化
editor.onDidChangeModelContent(() => {
const value = editor.getValue() // 給父組件實(shí)時(shí)返回最新文本
emit('update:modelValue', value)
emit('change', value)
})
emit('editor-mounted', editor)
}
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,
() => {
console.log('props.readOnly', props.readOnly)
editor.updateOptions({ readOnly: props.readOnly })
},
{ deep: true },
)
watch(
() => props.language,
(newValue) => {
monaco.editor.setModelLanguage(editor.getModel()!, newValue)
},
)
onBeforeUnmount(() => {
editor.dispose()
})
onMounted(() => {
init()
})
return { codeEditBox }
},
})
</script>
<style lang="scss" scoped>
.codeEditBox {
width: 100%;
flex: 1;
min-height: 100px;
// height: 200px;
overflow-y: auto;
}
.codeEditBox1{
height: calc(100% - 323px);
}
</style>
4.monacoEditorType.ts類型定義文件
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 // 自適應(yīng)布局
foldingStrategy: FoldingStrategy // 折疊方式 auto | indentation
renderLineHighlight: RenderLineHighlight // 行亮
selectOnLineNumbers: boolean // 顯示行號(hào)
placeholder:string
minimap: {
// 關(guān)閉小地圖
enabled: boolean
}
// readOnly: Boolean // 只讀
fontSize: number // 字體大小
scrollBeyondLastLine: boolean // 取消代碼后面一大段空白
overviewRulerBorder: boolean // 不要滾動(dòng)條的邊框
}
export const editorProps = {
modelValue: {
type: String as PropType<string>,
default: null,
},
hightChange: {
type: Boolean,
default: false,
},
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',
},
options: {
type: Object as PropType<Options>,
default() {
return {
automaticLayout: true,
// foldingStrategy: 'indentation',
foldingStrategy: 'indentation', // 折疊方式 auto | indentation
// renderLineHighlight: 'all',
renderLineHighlight: 'all' || 'line' || 'none' || 'gutter', // 行亮
selectOnLineNumbers: true, // 顯示行號(hào)
minimap: {
// 關(guān)閉小地圖
enabled: false,
},
placeholder: 'ss',
// readOnly: false, // 只讀
fontSize: 16, // 字體大小
scrollBeyondLastLine: false, // 取消代碼后面一大段空白
overviewRulerBorder: false, // 不要滾動(dòng)條的邊框
}
},
},
}
5.在父組件中使用
<monacoEditor
v-model="value"
:language="language"
:hight-change="hightChange"
:read-only="tablist.length===0"
width="100%"
height="100%"
@editor-mounted="editorMounted"
/>
import monacoEditor from './monacoEditor.vue'
const value = ref('-- select * from infrastructure;')
const language = ref('sql')
const hightChange = ref<any>(false)
const editorMounted = (editor: any) => {
console.log('editor實(shí)例加載完成', editor)
}
value:編輯器代碼顯示的值
language:要加載的語(yǔ)言類型
hightChange:改變編輯器的高度(可去掉,我這邊有個(gè)sql查表的實(shí)現(xiàn),需要在編輯區(qū)下面加一個(gè)sql查詢的表格,所以需要這個(gè)參數(shù))
read-only:編輯區(qū)是否是只讀的,當(dāng)左側(cè)文件樹為空時(shí)沒(méi)有文件,編輯區(qū)不可寫
editorMounted:加載完成操作
//記得在env.d.ts配置包的 declare module 'monaco-editor'; declare module 'monaco-editor/esm/vs/language/typescript/ts.worker?worker' declare module 'monaco-editor/esm/vs/basic-languages/sql/sql.js'; declare module 'monaco-editor/esm/vs/basic-languages/yaml/yaml.js'; declare module 'monaco-editor/esm/vs/language/json/json.worker?worker' declare module 'monaco-editor/esm/vs/language/css/css.worker?worker' declare module 'monaco-editor/esm/vs/language/html/html.worker?worker' declare module 'monaco-editor/esm/vs/editor/editor.worker?worker' declare module 'monaco-editor/esm/vs/basic-languages/javascript/javascript.js'
打包報(bào)錯(cuò)的處理
yarn build 時(shí)會(huì)發(fā)生下述報(bào)錯(cuò)

我在這里看到了解決辦法https://github.com/microsoft/monaco-editor/blob/main/docs/integrate-esm.md
在monacoEditor.vue組件,重寫getWorker方法
<template>
<div
ref="codeEditBox"
class="codeEditBox"
:class="hightChange&&'codeEditBox1'"
/>
</template>
<script lang="ts">
import {
defineComponent, onBeforeUnmount, onMounted, ref, watch,
} from 'vue'
// 減去以下包
-- 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'
-- import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import * as monaco from 'monaco-editor'
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
import { language as yamlLanguage } from 'monaco-editor/esm/vs/basic-languages/yaml/yaml.js';
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution'
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
import { editorProps } from './monacoEditorType'
export default defineComponent({
name: 'MonacoEditor',
props: editorProps,
emits: ['update:modelValue', 'change', 'editor-mounted'],
setup(props, { emit }) {
(self as any).MonacoEnvironment = {
++ getWorker: (_: string, label: string) => {
++ const getWorkerModule = (moduleUrl:string, label:string) => new Worker((self as any).MonacoEnvironment.getWorkerUrl(moduleUrl), {
++ name: label,
++ type: 'module',
++ });
++ switch (label) {
++ case 'json':
++ return getWorkerModule('/monaco-editor/esm/vs/language/json/json.worker?worker', label);
++ case 'css':
++ case 'scss':
++ case 'less':
++ return getWorkerModule('/monaco-editor/esm/vs/language/css/css.worker?worker', label);
++ case 'html':
++ case 'handlebars':
++ case 'razor':
++ return getWorkerModule('/monaco-editor/esm/vs/language/html/html.worker?worker', label);
++ case 'typescript':
++ case 'javascript':
++ return getWorkerModule('/monaco-editor/esm/vs/language/typescript/ts.worker?worker', label);
++ default:
++ return getWorkerModule('/monaco-editor/esm/vs/editor/editor.worker?worker', label);
++ }
++ },
// 原來(lái)的減去
-- getWorker(_: string, label: string) {
-- if (label === 'json') {
-- return new JsonWorker()
-- }
-- if (['css', 'scss', 'less'].includes(label)) {
-- return new CssWorker()
-- }
-- if (['html', 'handlebars', 'razor'].includes(label)) {
-- return new HtmlWorker()
-- }
-- if (['typescript', 'javascript'].includes(label)) {
-- return new TsWorker()
-- }
-- return new EditorWorker()
-- },
}
let editor: any
const codeEditBox = ref()
const init = () => {
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: false,
})
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2020,
allowNonTsExtensions: true,
})
monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems() {
const suggestions:any = [];
// 這個(gè)keywords就是sql.js文件中有的
sqlLanguage.keywords.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: item,
});
})
sqlLanguage.operators.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Operator,
insertText: item,
});
})
sqlLanguage.builtinFunctions.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Function,
insertText: item,
});
})
sqlLanguage.builtinVariables.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Variable,
insertText: item,
});
})
return {
// 最后要返回一個(gè)數(shù)組
suggestions,
};
},
})
monaco.languages.registerCompletionItemProvider('yaml', {
provideCompletionItems() {
const suggestions:any = [];
// 這個(gè)keywords就是python.js文件中有的
yamlLanguage.keywords.forEach((item:any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: item,
});
})
return {
// 最后要返回一個(gè)數(shù)組
suggestions,
};
},
})
editor = monaco.editor.create(codeEditBox.value, {
value: props.modelValue,
language: props.language,
readOnly: props.readOnly,
theme: props.theme,
...props.options,
})
// 監(jiān)聽(tīng)值的變化
editor.onDidChangeModelContent(() => {
const value = editor.getValue() // 給父組件實(shí)時(shí)返回最新文本
emit('update:modelValue', value)
emit('change', value)
})
emit('editor-mounted', editor)
}
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,
() => {
console.log('props.readOnly', props.readOnly)
editor.updateOptions({ readOnly: props.readOnly })
},
{ deep: true },
)
watch(
() => props.language,
(newValue) => {
monaco.editor.setModelLanguage(editor.getModel()!, newValue)
},
)
onBeforeUnmount(() => {
editor.dispose()
})
onMounted(() => {
init()
})
return { codeEditBox }
},
})
</script>
<style lang="scss" scoped>
.codeEditBox {
width: 100%;
flex: 1;
min-height: 100px;
// height: 200px;
overflow-y: auto;
}
.codeEditBox1{
height: calc(100% - 323px);
}
</style>

總結(jié)
到此這篇關(guān)于vue3+vite+ts使用monaco-editor編輯器的文章就介紹到這了,更多相關(guān)vue3+vite+ts使用monaco-editor內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue3+vite 動(dòng)態(tài)引用靜態(tài)資源及動(dòng)態(tài)引入assets文件夾圖片的多種方式
- vue3+vite assets動(dòng)態(tài)引入圖片的三種方法及解決打包后圖片路徑錯(cuò)誤不顯示的問(wèn)題
- vue3+vite+TS中使用element-plus按需引入ElLoading、ElMessage樣式失效解決
- Vue3+Ts實(shí)現(xiàn)父子組件間傳值的兩種方式
- vue3?父子組件間相互傳值方式
- vue3父子組件傳值中props使用細(xì)節(jié)淺析
- vue3 父子組件傳值詳解
- vue3+vite+ts父子組件之間的傳值
相關(guān)文章
vue實(shí)現(xiàn)從外部修改組件內(nèi)部的變量的值
這篇文章主要介紹了vue實(shí)現(xiàn)從外部修改組件內(nèi)部的變量的值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
實(shí)現(xiàn)一個(gè)Vue版Upload組件
這篇文章主要介紹了實(shí)現(xiàn)一個(gè)Vue版Upload組件,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
vue + socket.io實(shí)現(xiàn)一個(gè)簡(jiǎn)易聊天室示例代碼
本篇文章主要介紹了vue + socket.io實(shí)現(xiàn)一個(gè)簡(jiǎn)易聊天室示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
vue封裝el-upload批量上傳只請(qǐng)求一次接口
本文主要介紹了vue封裝el-upload批量上傳只請(qǐng)求一次接口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
圖文詳解Vue3沒(méi)有代碼提示問(wèn)題的解決辦法
最近在使用Vue.js時(shí)候沒(méi)有自動(dòng)提示,就很難受,下面這篇文章主要給大家介紹了關(guān)于Vue3沒(méi)有代碼提示問(wèn)題的解決辦法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01

