代码编辑器之monaco-editor 实现可编辑的git diff效果

MonacoEditor编辑器

简介

底层vscode开发的一款编辑器,各方面的样式功能基本与vscode一致。

官方文档

Monaco Editor (microsoft.github.io)

安装

安装时两者版本要对应,对应版本在后面,有时候版本对不上,会存在一定的问题。

sql 复制代码
npm install monaco-editor@0.28.1 --save-dev
npm install monaco-editor-webpack-plugin@4.2.0 --save-dev

常用属性

以下是较为常见的属性,其它属性可参考官网。

js 复制代码
value: this.editorValue, // 编辑器初始显示文字
theme: 'CodeSampleTheme', // 官方自带三种主题vs, hc-black, or vs-dark
language: 'json', // 支持json、js等,更多语言支持自行查阅demo,
overviewRulerBorder: false, // 滚动是否有边框
automaticLayout: true, // 自动布局
readOnly: false, // 是否只读
minimap: { // 关闭代码缩略图
  enabled: false // 是否启用预览图
},
lineNumbers: 'off', // 控制行号的显隐
scrollBeyondLastLine: false, // 禁用额外滚动区
scrollbar: {
  verticalScrollbarSize: 4, // 垂直滚动条宽度,默认px
  horizontalScrollbarSize: 4 // 水平滚动条高度
},
contextmenu: false // 禁用右键菜单

示例demo

第一步,配置monaco-editor-webpack-plugin

在项目中webpack的配置文件中,引入该plugin。

js 复制代码
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

module.exports = {
	...
	plugins: [new MonacoWebpackPlugin()]
};

第二步,封装vue组件

可以将组件命名为monaco-diff

vue 复制代码
<template>
    <div class="monaco-container">
      <div ref="container" class="monaco-editor" :style="{height:height,width:width}"></div>
    </div>
</template>
  
<script>
  import * as monaco from 'monaco-editor';
  export default {
    name: 'MonacoEditor',
    props: {
      prevCodes:{
        type: String,
        default: ''
      },
      currentCodes:{
        type: String,
        default: ''
      },
      width: {
        type: String,
        default: '400px'
      },
      height: {
        type: String,
        default: '500px'
      },
      readOnly: {
        type: Boolean,
        default: false
      },
      editorOptions:{
        type: Object,
        default: () => {
          return {
            originalEditable:true,
            selectOnLineNumbers: true,
            roundedSelection: false,
            readOnly: false,
            cursorStyle: 'line',
            automaticLayout: true,
            glyphMargin:true,// 字形边缘
            useTabStops:false,
            scrollBeyondLastLine: false,
            wordWrap: 'on',
            wordWrapColumn: 80,
            wrappingIndent: 'indent',
            autoIndent: true,
            formatOnPaste: true // 复制粘贴时格式化
        }
      },
      theme:{
        type: String,
        default: 'vs-dark'
      }
    },
    watch:{
      prevCodes(val){
        if(this.monacoEditor){
          const originModel=monaco.editor.createModel(val,'json');
          const modifyModel=monaco.editor.createModel(this.currentCodes,'json');
          this.monacoEditor.setModel({
            originModel:originModel,
            modifyModel:modifyModel
          })
        }
      },
      currentCodes(val){
        if(this.monacoEditor){
          const originModel=monaco.editor.createModel(this.prevCodes,'json');
          const modifyModel=monaco.editor.createModel(val,'json');
          this.monacoEditor.setModel({
            originModel:originModel,
            modifyModel:modifyModel
          })
        }
      }
    },
    mounted() {
      this.monacoEditor=monaco.editor.createDiffEditor(this.$refs.container,{
        language:'json',
        theme:this.theme,
        automaticLayout:true,
        diffCodeLens: true,
        readOnly:this.readOnly,
        ...this.editorOptions
      })
      const originModel=monaco.editor.createModel(this.prevCodes,'json');
      const modifyModel=monaco.editor.createModel(this.currentCodes,'json');
      this.monacoEditor.setModel({
        originModel:originModel,
        modifyModel:modifyModel
      })
    },
    beforeDestroy() {
      if(this.monacoEditor){
        this.monacoEditor.dispose();
      }
    },
}
}
</script>
  
<style lang="less" scoped>
  .monaco-container{
    border: 1px solid #ddd;
  }
</style>

第三步,引入组件

在业务组件中,引入上一步封装的组件,使用即可。

vue 复制代码
<template>
    <monaco-diff :preCodes="prevCodes" :currentCodes="currentCodes" ref="diffResultRef" />
</template>
  
<script>
  import monacoDiff from './monaco-diff'
  export default {
    components:{
      monacoDiff
    },
    data(){
      return {
        prevCodes:'',
        currentCodes:''
      }
    },
    mounted() {
      // 赋值的话正常把值赋值给prevCodes和currentCodes即可,比如下面这样
      this.prevCodes='{"name":"test","age":18,"sex":"男","address":"北京"}'
      this.currentCodes='{"name":"test","age":18,"sex":"男","address":"北京","phone":"13123123123"}'
    },
    methods: {
      // 获取编辑器两边的值
      getValue(){
        const {modified,original}=this.$refs.diffResultRef.monacoEditor.getModel();
        return {
          modified:modified.getValue(),
          original:original.getValue()
        }
      }
    },
}
</script>
  
<style>
  
</style>

就能看到两边内容类似git diff的效果了

不得不说monaco编辑器真的是很强大,基本上很多编辑器功能都可以实现了,各种语言支持,代码智能提示等。

相关推荐
Highcharts.js6 分钟前
Highcharts 使用指南Treegraph chart 树状图/结构树图|创建谱系图表、决策树、结构知识树等的图表工具
javascript·决策树·highcharts·图表开发·结构树·可视化图表库·谱系图表
进击切图仔8 分钟前
执行 shell 脚本 5 种方式对比
前端·chrome
局i9 分钟前
React 简单地图组件封装:基于高德地图 API 的实践(附源码)
前端·javascript·react.js
执行部之龙19 分钟前
AI对话平台核心技术解析
前端
进击的尘埃21 分钟前
Service Worker + stale-while-revalidate:让页面"假装"秒开的正经方案
javascript
yuki_uix23 分钟前
防抖(Debounce):从用户体验到手写实现
前端·javascript
HelloReader24 分钟前
Flutter 进阶 UI搭建 iOS 风格通讯录应用(十一)
前端
wjj不想说话24 分钟前
在 Vue 2.6 微前端架构中,我们为什么放弃了 Vuex 管理页面状态?
vue.js
张元清25 分钟前
每个 React 开发者都需要的 10 个浏览器 API Hooks
前端·javascript·面试
进击的尘埃27 分钟前
给 Claude Code 造个趁手的 MCP Tool Server,聊聊我踩的那些坑
javascript