vue3 使用 monaco-editor 自定义代码补全。
使用场景:
数据编辑时需要支持sql语法高亮, 并且支持自定义代码提示补全。
monaco详细说明和使用可参考另一篇发文Monaco Editor (vite/webpack ts vue项目使用)
步骤一:安装依赖
npm i monaco-editor
步骤二:组件功能封装
-
<template>
-
<div ref="cusEditor"></div>
-
</template>
-
<script setup lang="ts">
-
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
-
import { withDefaults, defineProps, ref, defineEmits, onMounted, onUnmounted, watch } from 'vue'
-
import { OPTIONS_BASE } from './registerCompletion'
-
import './worker'
-
interface IProps {
-
modelValue: string
-
disabled?: boolean
-
editorConfig?: { language: string; theme: 'vs' | 'vs-dark' | 'hc-black' }
-
}
-
const props = withDefaults(defineProps<IProps>(), {
-
modelValue: '',
-
disabled: false,
-
editorConfig: () => ({ language: 'sql', theme: 'vs-dark' }),
-
})
-
-
const cusEditor = ref<HTMLElement | null>(null)
-
let editor: Partial<monaco.editor.IStandaloneCodeEditor> = {}
-
const emit = defineEmits(['update:modelValue'])
-
/**初始化编辑器 */
-
onMounted(() => {
-
onDispose()
-
if (cusEditor.value) {
-
editor = monaco.editor.create(cusEditor.value, { ...OPTIONS_BASE, ...props.editorConfig, readOnly: props.disabled })
-
editor.onDidChangeModelContent &&
-
editor.onDidChangeModelContent(() => {
-
const value = editor.getValue && editor.getValue() // 给父组件实时返回最新文本
-
emit('update:modelValue', value)
-
})
-
}
-
})
-
/**销毁实例 */
-
const onDispose = () => {
-
editor && editor.dispose && editor.dispose()
-
}
-
onUnmounted(() => {
-
onDispose()
-
})
-
/**修改只读状态 */
-
watch(
-
() => props.disabled,
-
(val) => {
-
editor.updateOptions && editor.updateOptions({ readOnly: val })
-
}
-
)
-
/**修改配置 */
-
watch(
-
() => props.editorConfig,
-
(val) => {
-
const model = editor.getModel && editor.getModel()
-
if (model) {
-
monaco.editor.setModelLanguage(model, val.language)
-
monaco.editor.setTheme(val.theme)
-
}
-
},
-
{ deep: true }
-
)
-
/**回显数据 */
-
watch(
-
() => props.modelValue,
-
(val) => {
-
if (editor) {
-
const value = editor.getValue && editor.getValue()
-
if (val !== value) {
-
editor.setValue && editor.setValue(val || '')
-
}
-
}
-
}
-
)
-
</script>
- OPTIONS_BASE : 为基础配置,具体参数可参考官网
- worker: 解决vite引入代码高亮和错误提示
OPTIONS_BASE:
-
export const OPTIONS_BASE: monaco.editor.IStandaloneEditorConstructionOptions = {
-
value: '', // 初始显示文字
-
lineNumbers: 'on', // 是否展示行号 'off' | 'on
-
automaticLayout: false, // 自适应布局 默认true
-
minimap: {
-
enabled: false,
-
},
-
tabSize: 2,
-
fontSize: 16
-
}
worker.ts
-
import * as monaco from 'monaco-editor';
-
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()
-
}
-
}
-
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
步骤三:组件的使用
-
<template>
-
<el-form-item label="表名:" prop="table">
-
<MonacoEditor class="w-full h-40" v-model="formData.table" :disabled="disabled" :constModelData="constModelData"></MonacoEditor>
-
</el-form-item>
-
</template>
-
<script lang="ts" setup>
-
import MonacoEditor from '@/components/monaco/index.vue'
-
</script>
到此,就可以实现基础的编辑功能
*扩展
由于我项目中使用的时sql语法,并且还需要支持自定义代码补全, 接下来就以sql语言为例:
步骤一:自定义补全语法方法封装
-
import * as monaco from 'monaco-editor';
-
/**
-
* 注册:自定义语法补全
-
* @param language 语言类型
-
* @param constValues 常量提示
-
*/
-
export const registerProvider = (language: string, constValues: string[]) => {
-
const monacoProvider = monaco.languages.registerCompletionItemProvider(language, {
-
provideCompletionItems: function (model, position) {
-
// 获取当前行数
-
const line = position.lineNumber
-
// 获取当前列数
-
const column = position.column
-
// 获取当前输入行的所有内容
-
const content = model.getLineContent(line)
-
// 通过下标来获取当前光标后一个内容,即为刚输入的内容
-
const sym = content[column - 2]
-
const word = model.getWordUntilPosition(position)
-
const range = {
-
startLineNumber: position.lineNumber,
-
endLineNumber: position.lineNumber,
-
startColumn: word.startColumn,
-
endColumn: word.endColumn,
-
}
-
let suggestions: any[] = []
-
if (sym === '$') {
-
suggestions = constValues.map((e) => ({
-
label: e,
-
kind: monaco.languages.CompletionItemKind.Keyword,
-
insertText: '{' e '}',
-
detail: '常量配置',
-
}))
-
//拦截到用户输入$,开始设置提示内容,同else中代码一致,自行拓展
-
} else if(language === 'sql'){
-
// 直接提示,以下为sql语句关键词提示
-
var sqlStr = ['SELECT', 'FROM', 'WHERE', 'AND', 'OR', 'LIMIT', 'ORDER BY', 'GROUP BY', 'LEFT', 'ON', 'if(){}', 'for(){}', 'size', 'get()', 'substring', 'return']
-
suggestions = sqlStr.map((e) => ({
-
label: e, // 显示的提示内容
-
kind: monaco.languages.CompletionItemKind['Function'], // 用来显示提示内容后的不同的图标
-
insertText: e, // 选择后粘贴到编辑器中的文字
-
detail: '', // 提示内容后的说明
-
range: range,
-
}))
-
}
-
return {
-
suggestions: suggestions,
-
}
-
},
-
triggerCharacters: ['$', ''],
-
})
-
return monacoProvider
-
}
步骤二: 组件中使用
-
import { registerProvider } from '@/components/monaco/registerCompletion'
-
const registerPro = registerProvider('sql', props.constModelData)
效果展示:
1.sql关键字提示
2.常量提示:
问题:每打开一次编辑弹框, 常量的提示就多一条重复数据。如图:
原因: registerCompletionItemProvider多次注册。由于自定义补全注册的代码写在了编辑弹框中,所以每打开一次弹框就执行一次注册自定义补全的方法,。
解决方案一:将注册方法移动到最外层组件中可解决
但是 由于功能需求,常量的提示内容要根据每次打开的弹框数据改变, 所以注册方法必须写在内部,(编辑弹框打开后,需根据弹框绑定数据的id去请求常量接口, 然后注册)
解决方案:参考官方:https://github.com/microsoft/monaco-editor/issues/2084
解决方案二:dispose(), 页面卸载时,销毁之前注册的实例
-
const registerPro = registerProvider('sql', props.constModelData)
-
onUnmounted(() => {
-
registerPro && registerPro.dispose()
-
})
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhigkabb
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
excel下划线不显示怎么办
PHP中文网 06-23 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel图片置于文字下方的方法
PHP中文网 06-27 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22