二、配置vite.config.js

import { defineConfig } from 'vite'
import monacoEditorPlugin from "vite-plugin-monaco-editor"
export default defineConfig({
  plugins: [
    monacoEditorPlugin()
// 全局导入
import * as monaco from 'monaco-editor'
// 局部导入需要的功能和依赖
import * as monaco from 'monaco-editor/esm/vs/editor/edcore.main'
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'

2.封装组件

<template>
    <div id="code"></div>
</template>
<script setup>
  import * as monaco from 'monaco-editor/esm/vs/editor/edcore.main'
  import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
  // import { language } from 'monaco-editor/esm/vs/basic-languages/sql/sql'
  // language.keywords插件自带关键词的不全,网上找了一份自己维护
  import sqlKeywords from './sqlKeywords.js'
  const props = defineProps({
    database: {
      type: String,
      default: ''
  const editor = ref(null)
  const initEditor = () => {
    // 初始化编辑器,确保dom已经渲染
    editor.value = monaco.editor.create(document.getElementById('code'), {
      //初始化配置
      value: props.value,
      theme: 'vs-dark',
      autoIndex: true,
      language: 'sql', // 语言类型
      tabCompletion: 'on',
      cursorSmoothCaretAnimation: true,
      formatOnPaste: true,
      mouseWheelZoom: true,
      folding: true, //代码折叠
      autoClosingBrackets: 'always',
      autoClosingOvertype: 'always',
      autoClosingQuotes: 'always',
      automaticLayout: 'always'
  // 父组件获取值
  const handleValue = () => {
    return toRaw(editor.value).getValue()
  // 父组件设置值
  const setValue = (content) => {
    toRaw(editor.value).setValue(content)
  onMounted(() => {
    initEditor()
  defineExpose({
    handleValue,
    setValue
</script>
 

自定义提示

const suggestion = ref(null)
  // 数据库对应的表名
  const hintData = reactive({
    a: ['group', 'area'],
    b: ['user', 'client']
  // 表对应的字段名
  const tableData = reactive({
    user: ['age', 'gender'],
    group: ['id', 'name']
  // 关键字提示
  const getSQLSuggest = () => {
    return sqlKeywords.map((key) => ({
      label: key,
      kind: monaco.languages.CompletionItemKind.Keyword,
      insertText: key,
      detail: 'keyword'
  // 表名提示
  const getTableSuggest = (dbName) => {
    const tableNames = hintData[dbName]
    if (!tableNames) {
      return []
    return tableNames.map((name) => ({
      label: name,
      kind: monaco.languages.CompletionItemKind.Constant,
      insertText: name,
      detail: dbName
  // 字段名提示
  const getParamSuggest = (tableName) => {
    const params = tableData[tableName]
    if (!params) {
      return []
    return params.map((name) => ({
      label: name,
      kind: monaco.languages.CompletionItemKind.Constant,
      insertText: name,
      detail: 'param'
  // 数据库名提示
  const getDBSuggest = () => {
    return Object.keys(hintData).map((key) => ({
      label: key,
      kind: monaco.languages.CompletionItemKind.Enum,
      insertText: key,
      detail: 'database'
const initEditor = () => {
 suggestion.value = monaco.languages.registerCompletionItemProvider('sql', {
        // 触发条件,也可以不写,不写的话只要输入满足label就会提示
        // 只能配置单字符
        triggerCharacters: ['.', ' '],
        provideCompletionItems: (model, position) => {
            let suggestions = []
            const { lineNumber, column } = position
            const textBeforePointer = model.getValueInRange({
                startLineNumber: lineNumber,
                startColumn: 0,
                endLineNumber: lineNumber,
                endColumn: column,
            const tokens = textBeforePointer.toLocaleLowerCase().trim().split(/\s+/)
            const lastToken = tokens[tokens.length - 1] // 获取最后一段非空字符串
            const word = model.getWordUntilPosition(position)
            const range = {
              startLineNumber: position.lineNumber,
              endLineNumber: position.lineNumber,
              startColumn: word.startColumn,
              endColumn: word.endColumn
            if (lastToken.endsWith('.')) {
            // 提示该数据库下的表名
                const tokenNoDot = lastToken.slice(0, lastToken.length - 1)
                if (Object.keys(hintData).includes(tokenNoDot)) {
                    suggestions = [...getTableSuggest(tokenNoDot)]
            } else if (lastToken === '.') {
                suggestions = []
            } else if (textBeforePointer.endsWith(' ')) {
              if (textBeforePointer.endsWith('select * from ')) {
                // select * from 提示指定数据库的表名
                suggestions = getTableSuggest(props.database)
              } else if (lastToken === 'where') {
                // select * from tableName where 提示指定表的字段名
                const lastToken2 = tokens[tokens.length - 2]
                const lastToken3 = tokens[tokens.length - 3]
                const lastToken4 = tokens[tokens.length - 4]
                const lastToken5 = tokens[tokens.length - 5]
                if (lastToken5 + lastToken4 + lastToken3 === 'select*from') {
                  suggestions = [...getParamSuggest(lastToken2)]
                } else {
                  suggestions = []
              }else {
                suggestions = []
            } else {
                // 提示数据库名和关键词
                suggestions = [...getDBSuggest(), ...getSQLSuggest()]
            return {
                suggestions
 reg += '/'
 color.value = monaco.languages.setMonarchTokensProvider('sql', {
    ignoreCase: true,
    tokenizer: {
      root: [
            { token: 'keyword' },
        ], //蓝色
            /[+]|[-]|[*]|[/]|[%]|[>]|[<]|[=]|[!]|[:]|[&&]|[||]/,
            { token: 'string' },
        ], //红色
        [/'.*?'|".*?"/, { token: 'string.escape' }], //橙色
        [/#--.*?\--#/, { token: 'comment' }], //绿色
        [/null/, { token: 'regexp' }], //粉色
        [/[{]|[}]/, { token: 'type' }], //青色
        [/[\u4e00-\u9fa5]/, { token: 'predefined' }],//亮粉色
        [/''/, { token: 'invalid' }],//红色
        [/[\u4e00-\u9fa5]/, { token: 'number.binary' }],//浅绿
        [/(?!.*[a-zA-Z])[0-9]/, { token: 'number.hex' }], //浅绿
        [/[(]|[)]/, { token: 'number.octal' }], //浅绿
        [/[\u4e00-\u9fa5]/, { token: 'number.float' }],//浅绿
 

 格式化代码&标记错误

yarn add  sql-formatter -D

import { format } from 'sql-formatter'
const initEditor = () => {
 // 改写插件自带格式化功能
 formatProvider.value = monaco.languages.registerDocumentFormattingEditProvider('sql', {
	provideDocumentFormattingEdits(model) {
		return [{
			text: formatSql(1),
			range: model.getFullModelRange()
 // 格式化代码
 const formatSql = (needValue) => {
	clearMistake()
	try {
	    setValue(format(toRaw(editor.value).getValue()))
	} catch (e) {
		const {message} = e
		const list = message.split(' ')
		const line = list.indexOf('line')
		const column = list.indexOf('column')
		markMistake({
	        startLineNumber: Number(list[line + 1]),
			endLineNumber: Number(list[line + 1]),
			startColumn: Number(list[column + 1]),
			endColumn: Number(list[column + 1])
		}, 'Error', message)
	if (needValue) {
		 return toRaw(editor.value).getValue()
 // 标记错误信息
 const markMistake = (range, type, message) => {
	const {startLineNumber, endLineNumber, startColumn, endColumn} = range
	monaco.editor.setModelMarkers(
		  toRaw(editor.value).getModel(),
		  'eslint',
			startLineNumber,
			endLineNumber,
			startColumn,
			endColumn,
			severity: monaco.MarkerSeverity[type], // type可以是Error,Warning,Info
			message
 // 清除错误信息
 const clearMistake = () => {
	monaco.editor.setModelMarkers(
	    toRaw(editor.value).getModel(),
		'eslint',
const initEditor = () => {
    toRaw(editor.value).onDidChangeModelContent(() => {
        console.log('value', toRaw(editor.value).getValue())
 

销毁编辑器及其配置,防止自定义提示数据重复

onBeforeUnmount(() => {
    if (editor.value) {
      clearMistake()
      toRaw(editor.value).dispose()
      toRaw(color.value).dispose()
      toRaw(suggestion.value).dispose()
      toRaw(formatProvider.value).dispose()
				
Monaco Editor是一个非常强大的代码编辑器,它支持自定义代码补全。下面是在Vue中配置自定义代码补全的步骤: 1. 安装monaco-editor和monaco-editor-webpack-plugin npm install monaco-editor monaco-editor-webpack-plugin --save-dev 2. 在vue.config.js中添加配置: const MonacoEditorPlugin = require('monaco-editor-webpack-plugin'); module.exports = { configureWebpack: { plugins: [ new MonacoEditorPlugin({ // 你的语言模型文件路径 languages: ['path/to/your/language-model'], 3. 将monaco-editor组件添加到你的Vue组件: <template> <monaco-editor :language="language" :options="editorOptions" v-model="code" /> </template> <script> import * as monaco from 'monaco-editor'; export default { name: 'MyComponent', data() { return { code: '', language: 'javascript', editorOptions: { // 自定义代码补全 suggestOnTriggerCharacters: true, suggest: { customProvider: (model, position) => { // 这里是你的代码补全逻辑 return { suggestions: [ label: 'console.log', kind: monaco.languages.CompletionItemKind.Function, documentation: 'Log output to console', insertText: 'console.log(${1:object})', insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, range: new monaco.Range(position.lineNumber, 1, position.lineNumber, position.column), </script> 这里的suggest.customProvider是自定义代码补全的逻辑,你可以根据自己的需要进行改变。另外,你需要提供你的语言模型文件路径。