基于Vue2.X/Vue3.X对Monaco Editor在线代码编辑器进行封装与使用

2023-05-16

最近有个需求是显示日志模块的信息,用了好多在线代码编辑器,如各式各样的 markdown 啥的,都不太好使......

最后发现微软的 Monaco Editor 在线代码编辑器,这个插件就是牛!对此进行基于Vue2.X/Vue3.X的封装和使用。

// 查看 xxx 版本
格式:npm view xxx versions --json
举例:npm view monaco-editor versions --json

// monaco-editor 插件,必须
npm install monaco-editor --save-dev

// monaco-editor-webpack-plugin 插件,非必须
npm install monaco-editor-webpack-plugin --save-dev

// monaco-editor-nls 插件,非必须
npm install monaco-editor-nls --save-dev

// monaco-editor-esm-webpack-plugin 插件,非必须
npm install monaco-editor-esm-webpack-plugin --save-dev

// 引入 font-awesome 图标库,非必须
npm install font-awesome --save

父组件:index.vue

<template>
  <div class="monaco" style="padding: 100px;">
    <div class="monaco-left">
      <p align="center">
        <el-button type="primary" @click="handleMEContentChangeClick">OK</el-button>
      </p>
    </div>

    <div class="monaco-right">
      <MonacoEditor
        class="monaco-editor"
        ref="monacoEditorRef"
        :editorParams="editorParams">
      </MonacoEditor>
    </div>
  </div>
</template>

<script>
import MonacoEditor from './components/monacoEditor'

export default {
  components: {
    MonacoEditor
  },
  data: () => ({
    // editorParams 必填非空的代码编辑器参数
    editorParams: {
      id: 'monaco_ed_1',// 编辑器DOM节点ID
      title: '',// 编辑器标题
      content: '',// 编辑器内容
      height: '100%',// 编辑器高度
      readOnly: false,// 编辑器是否禁用
      isScrollToBottom: true // 是否滚动到底部
    }
  }),
  methods: {
    /**
     * 改变编辑器内容
     */
    handleMEContentChangeClick() {
      this.editorParams.content = 
        "\n" +
        "  .   ____          _            __ _ _\n" +
        " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n" +
        "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n" +
        " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n" +
        "  '  |____| .__|_| |_|_| |_\\__, | / / / /\n" +
        " =========|_|==============|___/=/_/_/_/\n" +
        " :: Spring Boot ::        (v2.2.5.RELEASE)\n" +
        "\n" +
        new Date() +
        "\n" +
        Math.random()
    }
  }
}
</script>

<style lang="less" scoped>
  .monaco {
    width: calc(100% - 200px);
    height: calc(100% - 200px);
    position: relative;
    display: flex;

    .monaco-left {
      width: 600px;
      height: 100%;
      background-color: #f8f8f8;
    }

    .monaco-right {
      width: calc(100% - 600px);
      height: 100%;
      background-color: #ff9b9b;

      .monaco-editor {
        height: 100%;
        overflow: hidden;
      }
    }
  }
</style>

子组件:monacoEditor.vue

<template>
  <div class="m-e" id="m-e-id">
    <div class="m-e-main">
      <div class="m-e-main_toolbar" :style="isThemeLightOrBlack ? 'background-color: #fff; box-shadow: 0px 2px 5px #ddd;' : 'background-color: #1e1e1e; box-shadow: 0px 2px 5px #111;'">
        <div class="m-e-main_toolbar_left">
          <span>日志 - {{ title }}</span>
        </div>
        
        <div class="m-e-main_toolbar_right" :style="isThemeLightOrBlack ? 'color: #000' : 'color: #fff'">
          <a title="查找" @click="findByKeyword"><i class="fa fa-search"/></a>
          <a title="回到顶部" @click="scrollToTop"><i class="fa fa-chevron-circle-up"/></a>
          <a title="回到底部" @click="scrollToBottom"><i class="fa fa-chevron-circle-down"/></a>
          <a title="是否截断换行" @click="setEditorWordWrap"><i class="fa fa-bars"/></a>
          <a title="切换白天或暗夜模式" @click="setEditorTheme"><i class="fa fa-adjust"/></a>
          <a :title="fullScreen ? '退出全屏' : '全屏显示'" @click="handleFullScreenClick"><i :class="fullScreen ? 'fa fa-compress' : 'fa fa-arrows-alt'"/></a>
          <a title="下载日志" @click="handleDownloadLogClick"><i class="fa fa-download" style="position: relative; top: 2px"/></a>
        </div>
      </div>
      <div :id="id" class="m-e-main_container" :style="'height: ' + height"></div>
    </div>
  </div>
</template>
 
<script>
// 引用 font-awesome 资源
import 'font-awesome/css/font-awesome.min.css';

// 先汉化 monaco
import { setLocaleData } from "monaco-editor-nls"
import zh_CN from "monaco-editor-nls/locale/zh-hans"
setLocaleData(zh_CN)

// 再加载 monaco ,才能汉化成功
import * as me from 'monaco-editor'

export default {
  props:[
    'editorParams'
  ],
  data: () => ({
    editor: null,// 编辑器对象
    id: null,// 编辑器DOM节点ID
    title: '',// 编辑器标题
    content: '',// 编辑器内容
    height: 'auto',// 编辑器高度
    readOnly: true,// 编辑器是否禁用
    isScrollToBottom: false, // 是否滚动到底部

    // 其他配置项...
    fullScreen: false,// 是否全屏状态
    wordWrap: false,// 当单行文本太长时截断换行,true 为换行,false 为不换行
    isThemeLightOrBlack: false,// 明亮或暗夜模式,true 为白天模式,false 为暗夜模式
    
  }),
  mounted() {
    /**
     * 监听全屏显示状态
     */
    let that = this;
    window.onresize = function() {
      if (!document.fullscreenElement) {
        that.fullScreen = false;
      } else {
        that.fullScreen = true;
      } 
    }
  },
  watch: {
    /**
     * 深度监听富文本参数
     */
    "editorParams": {
        handler: function(newVal, oldVal) {
          // console.log('newVal =>', newVal, ' | oldVal =>', oldVal);
          if (oldVal == null && newVal != null) {
            // 首次变化
            this.id = newVal.id;
            this.title = newVal.title;
            this.content = newVal.content;
            this.height = 'calc(' + newVal.height + ' - 42px)';
            this.readOnly = newVal.readOnly;
            this.isScrollToBottom = newVal.isScrollToBottom;
            this.initEditor(this.id, this.content, this.readOnly);
            if (this.isScrollToBottom) {
              this.scrollToBottom(); // 滚动到底部
            }
          } else if (newVal != null && newVal != null) {
            // 二次变化
            this.title = newVal.title;
            this.content = newVal.content;
            this.isScrollToBottom = newVal.isScrollToBottom;
            if (this.isScrollToBottom) {
              this.editor.setValue(this.content);
              this.scrollToBottom(); // 滚动到底部
            } else {
              this.editor.setValue(this.content);
            }
            // this.setEditorContent(this.content);
          }
        },
        immediate: true,
        deep: true
    },
  },
  methods: {
    /**
     * 实例化在线代码编辑器
     * 
     * 文档地址:https://microsoft.github.io/monaco-editor/api/index.html
     */
    async initEditor(id, content, readOnly) {
      // 异步获取节点,确保 Dom 节点已经渲染完成,不可删
      let dom = await document.getElementById(this.id);
      const monaco = require("monaco-editor/esm/vs/editor/editor.api");
      this.editor = monaco.editor.create(document.getElementById(id), {
          value: content,// 编辑器内容
          language: 'python',// 选择支持语言
          automaticLayout: true,// 是否自动布局
          theme: 'vs-dark',// 官方自带三种主题:vs、hc-black、vs-dark
          readOnly: readOnly,// 设置是否只读
          wordWrap: this.wordWrap ? 'on' : 'off',// 设置启用截断功能
          scrollBeyondLastLine: false,// 滚动完最后一行后再滚动一屏幕

          // 滚动条
          // scrollbar: {
          //   verticalScrollbarSize: 15,
          //   horizontalScrollbarSize: 15
          // },

          // 是否开启小地图
          minimap: {
            enabled: true
          },
      });

      // 设置编辑器滚动到最底部
      // this.scrollToBottom();
    },

    /**
     * 设置编辑器的内容且滚动到最底部
     */
    setEditorContent(val) {
      this.editor.setValue(val);
      this.scrollToBottom();
    },

    /**
     * 获取编辑器的内容
     */
    getEditorContent() {
      this.editor.getValue();
    },

    /**
     * 打开编辑器查找功能
     */
    findByKeyword() {
      try {
        // 先聚焦编辑器
        this.editor.focus();

        // 从模型中获取要查找的字符串范围 new Range(startLineNumber, startColumn, endLineNumber, endColumn)
        this.editor.setSelection(new me.Range(1, 9999, 1, 10000));

        // 触发查找操作
        // this.editor.getAction('actions.find').run();// 查找方式一
        this.editor.trigger('', 'actions.find');// 查找方式二
      } catch(error) {
        console.log(error);
      }
    },

    /**
     * 设置编辑器从只读变成可写
     */
    setEditorRW() {
      this.editor.updateOptions({readOnly: false});
    },

    /**
     * 设置编辑器开关截断功能
     */
    setEditorWordWrap() {
      this.wordWrap = this.wordWrap ? false : true;
      if (this.wordWrap) {
        this.editor.updateOptions({wordWrap: 'on'});
      } else {
        this.editor.updateOptions({wordWrap: 'off'});
      }
    },

    /**
     * 设置编辑器明亮或暗夜模式
     */
    setEditorTheme() {
      this.isThemeLightOrBlack = this.isThemeLightOrBlack ? false : true;
      if (this.isThemeLightOrBlack) {
        this.editor.updateOptions({theme: 'vs'});
      } else {
        this.editor.updateOptions({theme: 'vs-dark'});
      }
    },

    /**
     * 设置编辑器滚动到最顶部
     */
    scrollToTop() {
      this.editor.setScrollPosition({scrollTop: 0});
    },

    /**
     * 设置编辑器滚动到最底部
     */
    scrollToBottom() {
      // this.editor.revealLineInCenter(99999);
      this.editor.revealLine(this.editor.getModel().getLineCount());
    },

    /**
     * 全屏显示句柄
     */
    handleFullScreenClick () {
			const element = document.getElementById('m-e-id');
      if (!document.fullscreenElement) {
        element.requestFullscreen();
      } else {
        document.exitFullscreen();
      } 
    },

    /**
     * 下载日志句柄
     */
    handleDownloadLogClick() {
      this.exportFile(this.title, this.content);
    },

    /**
     * 下载日志
     */
    exportFile(name, data) {
      let url = window.URL || window.webkitURL || window;
      let blob = new Blob([data]);
      let event = document.createEvent("MouseEvents");
      event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
      let link = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
      link.href = url.createObjectURL(blob);
      link.download = name;
      link.dispatchEvent(event);
    }
  },
  /**
   * 销毁在线代码编辑器
   */
  beforeDestroy() {
    if (this.monacoEditor) {
      this.monacoEditor.dispose()
    }
  },
}
</script>
 
<style lang="less" scoped>
  .m-e {
    width: 100%;
    height: 100%;

    .m-e-main {
      width: 100%;
      height: 100%;

      .m-e-main_toolbar {
        width: 100%;
        height: 40px;
        box-shadow: 0px 2px 5px #000;
        display: flex;
        position: relative;
        z-index: 99;
    
        .m-e-main_toolbar_left {
          flex: 1;
          overflow: hidden;
    
          span {
            display: block;
            font-size: 15px;
            padding-left: 10px;
            line-height: 26px;
            line-height: 40px;
            white-space:nowrap;/* 不换行 */
            overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */
            text-overflow:ellipsis;/* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
            // user-select: none;
          }
        }
    
        .m-e-main_toolbar_right {
          margin-right: 15px;
    
          a {
            width: 16px;
            height: 16px;
            line-height: 16px;
            transition: ease all 0.3s ;
            text-align: center;
            display: inline-block;
            padding: 5px;
            cursor: pointer;
            border-radius: 2px;
            margin: 7px 0 7px 5px;
    
            i {
              font-size: 15px;
            }
    
            &:hover {
              background-color: rgba(255, 255, 255, 0.1);
            }
          }
        }
      }
    }
  }
</style>

最终效果:

以上代码在Vue3.X项目运行是有点问题的,页面会卡死,因为Vue3不再暴露子组件实例的属性和方法,但是却可以用toRaw方法获取到原始数据,也就是可以获取到子组件的实例,自然也就可以获取到实例的属性和方法。

例如获取编辑器内容方法,this.editor改为toRaw(this.editor)即可,还有其他方法也要改一下哦。

// 引入获取原始数据组件
import { toRaw } from 'vue'

/**
 * 获取编辑器的内容
 */
getEditorContent() {
  toRaw(this.editor).getValue();
},

好了,本次分享就到这里。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Vue2.X/Vue3.X对Monaco Editor在线代码编辑器进行封装与使用 的相关文章

  • C++进阶之路---STL---vector

    vector 一 xff1a vector简介二 vector的初始化方式三 vector的常见问题1 size 和capacity 的区别2 元素的构建方式3 访问容器内部元素的方式方式一 xff1a 方式二 xff1a error 有可
  • albumentations数据增强学习

    albumentations数据增强学习 96 96 文章目录 albumentations数据增强学习原图 xff1a CLAHE xff08 限制对比度自适应直方图均衡化 xff09 数据增强RandomRotate90 xff08 随
  • C++:STL迭代器

    11 23 STL迭代器 STL迭代器 顺序迭代器 遍历型迭代器 iterator 正向迭代器 reverse iterator 反向迭代器 span class token macro property span class token
  • 约瑟夫环C语言链表实现

    约瑟夫环 xff1a 设编号分别为1 2 3 n的n个人围坐一圈 xff0c 提前约定编号为k 1 k n 的人从1开始计数 xff0c 数到m的那个人淘汰出局 xff0c 他的下一个人又从1开始计数 xff0c 数到m的人再淘汰出局 xf
  • 链表C语言实现--单向链表

    线性结构的链式存储也称为链表 xff0c 相比于顺序表 xff0c 链表能够解决顺序表中空间资源浪费问题以及空间不足的问题 链表的每一个结点包含数据域和指针域 xff0c 而每一个结点在内存中的地址是不连续的 xff0c 且能适应动态变化
  • 循环链表C语言实现

    本文介绍循环链表中的单向循环链表 xff0c 双向循环链表两种 第一种 xff1a 单向循环链表 xff0c 是在单向链表的基础上 xff0c 尾结点不再指向NULL xff0c 而是指向头结点从而构成循环 如下图 xff1a 所以相比单向
  • 那些只有程序员才能看懂的冷笑话,用餐时间请勿点开。。。

    0 客户被绑 xff0c 蒙眼 xff0c 惊问 xff1a 想干什么 xff1f 对方不语 xff0c 鞭笞之 xff0c 客户求饶 xff1a 别打 xff0c 要钱 xff1f 又一鞭 xff0c 十万够不 xff1f 又一鞭 xff
  • TCP服务器/客户端的Linux下的代码实现,单向通信、双向通信

    tcp流程 服务器 xff1a socket gt bind gt listen gt accept gt read write or recv send gt close 客户端 xff1a socket gt connect gt re
  • UNIX域套接字的网络编程实现

    UNIX域套接字 socket同样可以用于本地通信 xff0c 即主机内的进程间通信 创建套接字时使用本地协议AF UNIX 或AF LOCAL 关于socket函数接口的介绍可参考我的另一篇博客 xff1a 链接 Linux网络基础介绍和
  • 堆排序、堆的定义、代码实现

    一 堆排序的定义 堆排序 xff08 Heapsort xff09 是指利用堆这种数据结构所设计的一种排序算法 二 堆的一些概念 1 堆的定义 堆是计算机科学中一类特殊的数据结构的统称 堆的逻辑结构 采用树形结构 xff0c 一般当做完全二
  • C++基础学习笔记

    说明 xff1a 此版只是C 43 43 基础学习的笔记 xff0c 涵盖内容有限 xff0c 知识点细节上也有所欠缺 xff0c 并未深入探讨各类机制的实现原理 所以在学习到相关知识点时建议参考其他博主的专门介绍的文章来深入学习 xff0
  • Qt基础介绍部分

    Qt是挪威一个团队开发的多平台C 43 43 图像用户界面应用程序框架 Qt是面向对象的框架 xff0c 使用特殊的代码生成扩展 Qt Creator是一个用于Qt开发的轻量级跨平台集成开发环境 支持跨平台开发 1 QT的优势 xff1a
  • UART协议讲解

    UART协议讲解 一 什么是UART协议二 通信方式的分类1 串行通信 xff08 一 xff09 同步通信和异步通信 xff08 二 xff09 单工和半双工以及全双工 2 并行通信 三 UART协议具体介绍1 UART数据传输的格式2
  • 常用的get、post请求有哪些

    常见的get post请求有哪些呢 常见的get请求有 form标签中method 61 get 发起的是get请求 a标签发起的是get请求 link标签引入css发起的是get请求 Script标签引入js文件发起的是get请求 img
  • 串口通信整理:二、数据发送之多位数据发送

    本文基于前一篇串口模块基础版进一步对串口发送数据整理 xff0c 并通过仿真进行验证 xff0c 所有代码都可直接跑通 xff0c 注意各个模块名字 首先再次回顾一下通信协议UART 本质就是并行数据转串行数据 关键参数 xff1a 起始位
  • HTTP协议解析

    文章目录 一 HTTP协议基础1 定义2 工作原理3 特点4 与Https的区别 x1f435 HTTPS简介 xff1a 两者区别 xff1a 二 HTTP请求协议1 HTTP请求结构 xff1a 2 请求方法3 举例4 Post和Get
  • Java httpUtil工具类

    需要导入的依赖 xff1a span class token generics span class token punctuation lt span dependency span class token punctuation gt
  • 博士申请 | 浙江大学孙优贤院士课题组招收智能无人系统方向硕士生/博士生

    合适的工作难找 xff1f 最新的招聘信息也不知道 xff1f AI 求职为大家精选人工智能领域最新鲜的招聘信息 xff0c 助你先人一步投递 xff0c 快人一步入职 xff01 浙江大学 网络传感与控制研究组 xff08 Group o
  • 文件解析__JSON解析

    一 JSON解析 1 简介 xff1a JSON是一种轻量级的数据交换格式 2 Java解析JSON 序列化 xff1a 将Java对象转换成JSON格式的数据 反序列化 xff1a 将JSON格式的数据转换成Java对象 import c
  • XSSFWorkbook,SXSSFWorkbook以及EasyExcel读取Excel文件的比较

    同时读取30w数据 xff0c 比较运行时间及CPU 内存占比 1 EasyExcel package com apesource import java util ArrayList import java util List impor

随机推荐

  • 基于FTP协议的文件上传与下载

    一 什么是FTP FTP 是File Transfer Protocol xff08 文件传输协议 xff09 的英文简称 xff0c 而中文简称为 文传协议 用于Internet上的控制文件的双向传输 同时 xff0c 它也是一个应用程序
  • MyBatis

    目录 优点 缺点 重难点问题 xff1a 1 传递多个参数 2 与 的区别 3 resultMap 元素 4 批处理 MyBatis 是一个开源 轻量级的数据持久化框架 xff0c 是 JDBC 和 Hibernate 的替代方案 MyBa
  • TCP协议的拥塞控制

    一 什么是拥塞控制 发送方需要维护一个状态变量 拥塞窗口cwnd 来决定发送方同时可以发送多少数据包 二 控制算法 1 慢开始 当主机开始传送数据时 xff0c 如果把大量数据注入 xff0c 可能会造成网络堵塞 所有 xff0c 为了避免
  • Autowired实现原理

    一 认识 64 Autowired 64 Autowired 替换 xff1a autowire属性 自动装配 xff08 按照类型装配 xff0c 通过set方法 xff0c 且方法可以省略 xff09 位置 xff1a 修饰属性 xff
  • JavaScript常用事件

    目录 鼠标 键盘事件 1 onclick 事件 2 onmouseover 事件 3 onmouseout 事件 4 onkeyup 事件 表单事件 1 onchange 事件 2 onfocus 事件 3 onblur 事件 鼠标 键盘事
  • 2020年电赛总结

    前言 前几天电赛的成绩公布了 xff0c 跟师哥们混了个省三等奖 xff0c 不管怎么说 xff0c 还是想写点东西 xff0c 来纪念一下这一年来的经历 正文 参加电赛可以说本来没有在我预料的范围之内 xff0c 基本上准备电赛所学习的知
  • 「C/C++」一些值得学习的C++开源库

    目录 说明BoostPocoOpenCVEigenSQLiteQtTensorFlow 说明 学习这些 C 43 43 开源库不仅可以提高我们的编程水平 xff0c 同时也可以提高我们的编程效率 xff0c 加速我们的应用程序开发 当然 x
  • Python中的__file__

    在Python项目开发过程中 xff0c 有的时候会获取程序文件的相对路径或者绝对路径 因此经常会见到如下的语句 xff1a import os os path dirname file 因此本文件这里的 file 是指明什么呢 xff1f
  • 记一下 Windows11 安装与配置 node.js 的标准步骤

    1 首先随便下载个 node js 的x86或x64 msi安装包 xff0c 双击直接安装 xff0c 安装的路径如 34 C Program Files nodejs 34 xff1b 2 安装完成后 xff0c 打开 cmd 命令控制
  • 什么是结构体内存对齐,有什么好处

    什么是结构体内存对齐 xff0c 有什么好处 下面先看一个例子 xff1a span class token macro property span class token directive keyword include span sp
  • 2.4G通信

    文章目录 2 4G无线通信实验一 模块简介二 Enhanced ShockBurstTM模式介绍三 编程1 初始化IO口2 Enhanced ShockBurstTM发送流程3 Enhanced ShockBurstTM发送模式初始化4 E
  • PTA非零返回的解决办法java

    应该不止我一个是在PTA做题遇到了 非零返回 导致不能AC xff0c 结果网上搜了一大堆相关资料按照步骤说的来改后依然没什么用的倒霉蛋吧 这是一件很无助的事情 xff0c 而且改代码真的很烦 造成非零返回的原因很多 xff0c 但是多数情
  • keil5的代码全是黑色不显示其他颜色/Colors&Fronts没有C/C++ Editor files选项(用于设置代码颜色)——安装路径不要有中文

    学习51单片机要用到keil5生成hex然后烧写文件 xff0c 但是在使用keil5的过程中遇到了一些小麻烦 C文件打开后代码全是黑色 xff0c 关键字等不显示高亮和其他不同颜色 xff0c 如下图所示 xff1a 是一个流水灯的小白程
  • keil5解决注释中文乱码问题

    xff08 1 xff09 Edit Configuration xff08 直接点击 xff0c 不用管它右边出现的东西 xff09 xff08 2 xff09 出现新的窗口之后 xff0c Editor Encoding Chinese
  • 嵌入式51/52单片机——流水灯实验小白教程(详细完整过程)Proteus 8配合Keil5仿真

    1 双击打开Proteus 2 打开下面显示的界面后 xff0c 点击 新建工程 3 跳出这个界面 4 修改名字为 流水灯 xff0c 点击浏览选择自己想放置的位置 xff08 根据个人需求 xff0c 不想改也可以用上面的默认路径 xff
  • 操作系统第一章阶段性测试题——教材:计算机操作系统(第4版)汤小丹、汤子瀛

    操作系统 xff08 第一章 xff09 阶段性测试 一 单选题 xff08 15 题 xff0c 每题 4 分 xff0c 共 60 分 xff09 1 操作系统负责管理计算机系统的 xff08 C xff09 xff0c 其中包括处理机
  • MarkdownPad2 解决“HTML渲染错误”

    在启动MarkdownPad2时 xff0c 出现了错误提示 xff1a HTML渲染组件出错 这个问题可以通过安装某个缺失组件来解决 您是否想要了解详细信息 xff1f 解决方法 xff1a 如它所说 xff0c 下载缺失的组件就可以了
  • 解决:IEDA在plugins里搜不到mybatisx插件

    1 打开setting 2 按照下图的步骤进行操作 xff0c URL直接复制 xff1a https plugins jetbrains com 粘贴到方框中 xff0c 记得要点apply和OK 3 点击plugins搜索mybatis
  • GitHub克隆别人的项目部署到IDEA运行的步骤

    第一步 xff1a 从Github上克隆项目 可以直接用URL也可以下载压缩包 xff0c 这里我直接下载压缩包 第二步 xff1a 把下载好的压缩包另存到你想要的目录下 xff0c 解压 第三步 xff1a 选择以管理员身份运行IDEA
  • 基于Vue2.X/Vue3.X对Monaco Editor在线代码编辑器进行封装与使用

    最近有个需求是显示日志模块的信息 xff0c 用了好多在线代码编辑器 xff0c 如各式各样的 markdown 啥的 xff0c 都不太好使 最后发现微软的 Monaco Editor 在线代码编辑器 xff0c 这个插件就是牛 xff0