美文网首页
Js代码编辑器

Js代码编辑器

作者: 等级7 | 来源:发表于2022-08-15 09:03 被阅读0次

在有些项目中有时需要让用户输入一些代码,使用户能自主处理一些数据逻辑,但如果让用户直接注入代码,会有很高的风险(恶意代码).
因此我们可以将用户输入的代码以字符串的形式传给后端,让后端根据所传的代码字符串处理数据.
为了使用户能有一个较好的代码输入体验,我们可以使用monaco-editor

npm install --save monaco-editor

使用的版本

  "monaco-editor": "^0.20.0",

组件MonacoEditor.vue文件

<template>
  <div ref="editor" class="main"></div>
</template>

<script>
  import * as monaco from 'monaco-editor'
  import createSqlCompleter from './util/sql-completion'
  import createJavascriptCompleter from './util/javascript-completion'
  import registerLanguage from './util/log-language'
  const global = {}

  const getHints = model => {
    let id = model.id.substring(6)
    return (global[id] && global[id].hints) || []
  }
  monaco.languages.registerCompletionItemProvider(
    'sql',
    createSqlCompleter(getHints)
  )
  monaco.languages.registerCompletionItemProvider(
    'javascript',
    createJavascriptCompleter(getHints)
  )
  registerLanguage(monaco)
  /**
   * monaco options
   * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
   */
  export default {
    props: {
      options: {
        type: Object,
        default () {
          return {}
        }
      },
      value: {
        type: String,
        required: false
      },
      language: {
        type: String
      },
      hints: {
        type: Array,
        default () {
          return []
        }
      }
    },
    name: 'MonacoEditor',
    data () {
      return {
        editorInstance: null,
        defaultOptions: {
          theme: 'vs-dark',
          fontSize: 14
        }
      }
    },
    watch: {
      value () {
        if (this.value !== this.editorInstance.getValue()) {
          this.editorInstance.setValue(this.value)
        }
      }
    },
    mounted () {
      this.initEditor()
      global[this.editorInstance._id] = this
      window.addEventListener('resize', this.layout)
    },
    destroyed () {
      this.editorInstance.dispose()
      global[this.editorInstance._id] = null
      window.removeEventListener('resize', this.layout)
    },
    methods: {
      layout () {
        this.editorInstance.layout()
      },
      undo () {
        this.editorInstance.trigger('anyString', 'undo')
        this.onValueChange()
      },
      redo () {
        this.editorInstance.trigger('anyString', 'redo')
        this.onValueChange()
      },
      getOptions () {
        let props = { value: this.value }
        this.language !== undefined && (props.language = this.language)
        let options = Object.assign({}, this.defaultOptions, this.options, props)
        return options
      },
      onValueChange () {
        this.$emit('input', this.editorInstance.getValue())
        this.$emit('change', this.editorInstance.getValue())
      },
      initEditor () {
        this.MonacoEnvironment = {
          getWorkerUrl: function () {
            return './editor.worker.bundle.js'
          }
        }
        this.editorInstance = monaco.editor.create(
          this.$refs.editor,
          this.getOptions()
        )
        this.editorInstance.onContextMenu(e => {
          this.$emit('contextmenu', e)
        })
        this.editorInstance.onDidChangeModelContent(() => {
          this.onValueChange()
        })
        this.editorInstance.addCommand(
          monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,
          () => {
            this.$emit('save', this.editorInstance.getValue())
          }
        )
      }
    }
  }
</script>
<style scoped>
.main /deep/ .view-lines * {
  font-family: Consolas, "Courier New", monospace !important;
}
</style>

Util/javascript-completion.js

/* eslint-disable */
 import * as monaco from 'monaco-editor'
// js 有内置提示
function createCompleter (getExtraHints) {
  const createSuggestions = function (model, textUntilPosition) {
    let text = model.getValue()
    textUntilPosition = textUntilPosition.replace(/[\*\[\]@\$\(\)]/g, '').replace(/(\s+|\.)/g, ' ')
    let arr = textUntilPosition.split(/[\s;]/)
    let activeStr = arr[arr.length - 1]
    let len = activeStr.length
    let rexp = new RegExp('([^\\w]|^)' + activeStr + '\\w*', 'gim')
    let match = text.match(rexp)
    let mergeHints = Array.from(new Set([...getExtraHints(model)]))
      .sort()
      .filter(ele => {
        let rexp = new RegExp(ele.substr(0, len), 'gim')
        return (match && match.length === 1 && ele === activeStr) ||
                    ele.length === 1 ? false : activeStr.match(rexp)
      })
    return mergeHints.map(ele => ({
      label: ele,
      kind: monaco.languages.CompletionItemKind.Text,
      documentation: ele,
      insertText: ele
    }))
  }
  return {
    provideCompletionItems (model, position) {
      let textUntilPosition = model.getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn: 1,
        endLineNumber: position.lineNumber,
        endColumn: position.column
      })
      return { suggestions: createSuggestions(model, textUntilPosition) }
    }
  }
}
export default createCompleter

Util/log-language.js

function registerLanguage (monaco) {
  monaco.languages.register({
    id: 'log'
  })
  monaco.languages.setMonarchTokensProvider('log', {
    tokenizer: {
      root: [
        [/(^[=a-zA-Z].*|\d\s.*)/, 'log-normal'],
        [/\sERROR\s.*/, 'log-error'],
        [/\sWARN\s.*/, 'log-warn'],
        [/\sINFO\s.*/, 'log-info'],
        [
          /^([0-9]{4}||[0-9]{2})-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{3})?/,
          'log-date'
        ],
        [
          /^[0-9]{2}\/[0-9]{2}\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{3})?/,
          'log-date'
        ],
        [/(^\*\*Waiting queue:.*)/, 'log-info'],
        [/(^\*\*result tips:.*)/, 'log-info']
      ]
    }
  })
  monaco.editor.defineTheme('log', {
    base: 'vs',
    inherit: true,
    rules: [{
      token: 'log-info',
      foreground: '4b71ca'
    },
    {
      token: 'log-error',
      foreground: 'ff0000',
      fontStyle: 'bold'
    },
    {
      token: 'log-warn',
      foreground: 'FFA500'
    },
    {
      token: 'log-date',
      foreground: '008800'
    },
    {
      token: 'log-normal',
      foreground: '808080'
    }
    ],
    colors: {
      'editor.lineHighlightBackground': '#ffffff',
      'editorGutter.background': '#f7f7f7'
    }
  })
}

export default registerLanguage

Util/sql-completion.js

/* eslint-disable */
 import * as monaco from 'monaco-editor'
const hints = [
  'SELECT',
  'INSERT',
  'DELETE',
  'UPDATE',
  'CREATE TABLE',
  'DROP TABLE',
  'ALTER TABLE',
  'CREATE VIEW',
  'DROP VIEW',
  'CREATE INDEX',
  'DROP INDEX',
  'CREATE PROCEDURE',
  'DROP PROCEDURE',
  'CREATE TRIGGER',
  'DROP TRIGGER',
  'CREATE SCHEMA',
  'DROP SCHEMA',
  'CREATE DOMAIN',
  'ALTER DOMAIN',
  'DROP DOMAIN',
  'GRANT',
  'DENY',
  'REVOKE',
  'COMMIT',
  'ROLLBACK',
  'SET TRANSACTION',
  'DECLARE',
  'EXPLAN',
  'OPEN',
  'FETCH',
  'CLOSE',
  'PREPARE',
  'EXECUTE',
  'DESCRIBE',
  'FROM',
  'ORDER BY']
function createCompleter (getExtraHints) {
  const createSuggestions = function (model, textUntilPosition) {
    let text = model.getValue()
    textUntilPosition = textUntilPosition.replace(/[\*\[\]@\$\(\)]/g, '').replace(/(\s+|\.)/g, ' ')
    let arr = textUntilPosition.split(/[\s;]/)
    let activeStr = arr[arr.length - 1]
    let len = activeStr.length
    let rexp = new RegExp('([^\\w]|^)' + activeStr + '\\w*', 'gim')
    let match = text.match(rexp)
    let textHints = !match ? []
      : match.map(ele => {
        let rexp = new RegExp(activeStr, 'gim')
        let search = ele.search(rexp)
        return ele.substr(search)
      })
    let mergeHints = Array.from(new Set([...hints, ...textHints, ...getExtraHints(model)]))
      .sort()
      .filter(ele => {
        let rexp = new RegExp(ele.substr(0, len), 'gim')
        return (match && match.length === 1 && ele === activeStr) ||
                    ele.length === 1 ? false : activeStr.match(rexp)
      })
    return mergeHints.map(ele => ({
      label: ele,
      kind: hints.indexOf(ele) > -1
        ? monaco.languages.CompletionItemKind.Keyword
        : monaco.languages.CompletionItemKind.Text,
      documentation: ele,
      insertText: ele
    }))
  }
  return {
    provideCompletionItems (model, position) {
      let textUntilPosition = model.getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn: 1,
        endLineNumber: position.lineNumber,
        endColumn: position.column
      })
      return { suggestions: createSuggestions(model, textUntilPosition) }
    }
  }
}
export default createCompleter

在使用的页面

 <monaco-editor
          v-model.trim="transformScript"
          language="javascript"
          style="height: 380px"
        />
  import MonacoEditor from '@/module/components/MonacoEditor/MonacoEditor'
 transformScript: '', // 执行代码文本

相关文章

  • 网页代码编辑器插件ace

    【实战精讲】网页嵌入代码展示/编辑器 导入相应的js文件,然后写代码html和js初始化

  • 前后端代码样式轮子

    HTML编程技巧-达达 1 解决滚动条影响布局 2 百度富文本编辑器 ①js代码引入 ②html代码引入 ③JS控...

  • Js代码编辑器

    在有些项目中有时需要让用户输入一些代码,使用户能自主处理一些数据逻辑,但如果让用户直接注入代码,会有很高的风险(恶...

  • 泰德仁和科技-前端学习

    软件准备 开发环境 Node.js 编辑器 sumlime 代码管理 git 开始学习 下载代码 项目目录 安装依...

  • web前端一些插件工具

    记录自己在项目中使用过的web工具 1、ace.js:基于JS的代码带高亮编辑器 在项目中只使用了它的代码高亮功能...

  • 常用资源

    GitHub 码云 Gitee — 开源中国 Git 代码托管平台 JSRUN在线JS编辑器 JSON在线解析及格...

  • 【JS】代码高亮编辑器 ace.js

    瞎扯 ace 是 js 实现的代码编辑器 编译打包之后的 ACE 代码 官网,未提供编译好的文件 ACE 拥有的特...

  • 代码编辑器 WebStorm v2019.2.3 中文便携版

    WebStorm 是 jetbrains 公司旗下一款 JavaScript 代码编辑器。目前已经被广大中国 JS...

  • HTML-标签

    一. Sublime安装和使用 Sublime是一个代码编辑器,可以编写HTML,php,js,css等等文件。 ...

  • #2 从零开始制作在线 代码编辑器

    上一篇#1 从零开始制作在线 代码编辑器 Line harusame-line.js 在serval/script...

网友评论

      本文标题:Js代码编辑器

      本文链接:https://www.haomeiwen.com/subject/eopkgrtx.html