最近因为需要实现一个在线代码的需求,所以研究了相关的内容,其中最主要的就是编辑器相关的内容

使用

对于 monaco 编辑器的选择,我使用了 @monaco-editor/react

import type { EditorProps, OnChange, OnMount } from '@monaco-editor/react'
import { Editor as MonacoEditor } from '@monaco-editor/react'
import { useDebounceFn } from 'ahooks'
import { Spin } from 'antd'
import { FC, useState } from 'react'

export const CodeEditor: FC<EditorProps> = props => {
  const [theme, setTheme] = useState('vs')

  // 处理代码修改, args需要做一层透传来完善防抖,避免触发重复构建
  const { run: handleChange } = useDebounceFn<OnChange>(
    (...args) => {
      if (props.onChange) {
        props.onChange(...args)
      }
    },
    {
      wait: 400,
    },
  )

  return (
    <MonacoEditor
      loading={<Spin />}
      theme={theme}
      {...props}
      onChange={handleChange}
    />
  )

简单的对齐进行了封装使用

本地使用

在使用 @monaco-editor/react 库,会通过CDN去加载编辑器的资源

Untitled

Untitled

但有时候,我们所需要的环境,并不能直接去访问外网,故我们需要将这些资源改变成本地加载 首先我们需要一个公共位置去存放这些资源,如 vite 的 public 文件夹等等 我们需要把 monaco-editor 库下载下来,主要是需要 min/vs 内容,提供给编辑器

其实还有另一种方式,是安装 monaco-editor 库,并引入即可,但之前测试的时候是有问题的,包括 webpack 等等,不太稳定,所以没有选择这种方式

import { loader } from '@monaco-editor/react'

loader.config({
  paths: {
    // public 下存放 monaco-editor 的路径
    vs: '/npm/monaco-editor/min/vs',
  },
})

通过这种方式,就可以避免编辑器去加载远程资源了

类型提示

在在线代码里,我们还需要自定义一些专属的东西,如全局上下文等内容

通过 Suggestion 提供类型提示

Monaco Editor (microsoft.github.io)

基本的操作方法可以查看一下官网的案例 主要就是通过 monaco.languages.registerCompletionItemProvider 方法去注册,然后返回规定格式的 suggestion 即可,最后再选择一个触发方式,即 triggerCharacters

monaco.languages.registerCompletionItemProvider('javascript', {
  provideCompletionItems: (model, position) => {
    const range = {
      startLineNumber: position.lineNumber,
      endLineNumber: position.lineNumber,
      startColumn: model.getWordUntilPosition(position).startColumn,
      endColumn: model.getWordUntilPosition(position).endColumn,
    }

    return {
      suggestions: [
        {
          label: 'test', // 显示的提示内容
          kind: monaco.languages.CompletionItemKind.Function, // 用来显示提示内容后的不同的图标
          insertText: 'test', // 选择后粘贴到编辑器中的文字
          detail: '', // 提示内容后的说明
          range: range,
        },
      ],
    }
  },
  triggerCharacters: ['.'],
})

上面代码实现的就是按下 . 时触发提示,并提示出 test 方法