Vue2 集成 CodeMirror 实现公式编辑、块状文本编辑,TAG标签功能

news/2024/7/9 23:54:12 标签: vue

效果图

 安装codemirror依赖

本示例为Vue2项目,安装低版本的依赖

npm i codemirror@5.65.12
npm i vue-codemirror@4.0.6

实现

实现代码如下,里边涉及到的变量和函数自行替换即可,没有其他复杂逻辑。

<template>
  <div class="picker">
    <div class="code-edit">
      <div class="top-title">公式</div>
      <codemirror
              ref="codeEditor"
              v-model="formulaStr"
              :options="cmOptions"
              @input="codeMirrorChange"
      ></codemirror>

    </div>
    <el-button
            size="mini"
            icon="el-icon-setting"
            @click="insertContent('表单4', 'variable')"
    >添加变量
    </el-button
    >
    <el-button
            size="mini"
            icon="el-icon-setting"
            @click="insertContent('SUM', 'func')"
    >添加函数
    </el-button
    >
  </div>

</template>

<script>
import {codemirror} from "vue-codemirror";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/idea.css";

export default {
  components: {codemirror},
  data() {
    return {
      cmOptions: {
        // 语言及语法模式
        mode: 'text/javascript',
        // 主题
        theme: "idea",
        // 显示函数
        line: true,
        lineNumbers: false,
        // 软换行
        lineWrapping: true,
        // tab宽度
        tabSize: 4,
      },
      lang: 'javascript',
      formulaStr: "表单 表单1 * 表单11*表单12+SUM(1,2) AVG(99,21) IF()",
    };
  },
  computed: {
    editor() {
      return this.$refs.codeEditor.codemirror;
    }
  },
  mounted() {
    this.focus(this.formulaStr)
    this.autoMarkText()
  },
  methods: {
    codeMirrorChange() {
      //获取 editor 的内容
      console.log("content1: " + this.formulaStr);
      console.log("content2: " + JSON.stringify(this.editor.getValue()));
    },
    addFormula(content, type) {
      this.insertContent(content, type)
    },
    /**
     * editor 中的对内容进行处理
     * @param value
     * @param type variable | func,variable为表单变量,需标记,func 为函数,也需要做标记
     */
    insertContent(value, type) {
      const from = this.editor.getCursor();
      if (type === 'variable') {
        this.editor.replaceSelection(value);
        const to = this.editor.getCursor();
        this.markText(from, to, value, 'cm-field');
      } else if (type === 'func') {
        this.editor.replaceSelection(`${value}()`);
        const to = this.editor.getCursor();
        this.markText(from, {line: to.line, ch: to.ch - 2}, value, 'cm-func');
        this.editor.setCursor({line: to.line, ch: to.ch - 1});
      } else if (typeof value === 'string') {
        this.editor.replaceSelection(value);
      }
      this.editor.focus();
    },

    autoMarkText() {
      if (this.formulaStr) {
        this.autoMark(this.formulaStr);
        this.focus(this.formulaStr);
      }
    },
    focus(value) {
      this.editor.setCursor({
        line: 0,
        ch: value ? value.length : 0
      });
      this.editor.focus()
    },
    markText(from, to, label, className) {
      if (className === void 0) {
        className = "cm-func";
      }
      let text = document.createElement("span");
      text.className = className;
      text.innerText = label;
      this.editor.markText(from, to, {
        atomic: true,
        replacedWith: text,
      });
    },
    /**
     * 解析 editor 的内容,分别对表单变量和函数进行标记
     */
    autoMark() {
      const editor = this.editor;
      const lines = editor.lineCount();
      for (let line = 0; line < lines; line++) {
        const content = editor.getLine(line);
        // 标记函数调用,匹配一个或多个连续的大写字母,后面可以有任意数量的空白字符,再紧跟一个左括号
        content.replace(/([A-Z]+)\s*\(/g, (_, func, pos) => {
          this.markText({line: line, ch: pos}, {line: line, ch: pos + func.length}, func, 'cm-func');
          return _;
        });
        // 标记表单变量,这应该是动态获取,自行替换即可
        let vars = ["表单", "表单1", "表单11", "表单12"];
        vars.forEach(v => {
          let from = 0;
          let idx = -1;
          while (~(idx = content.indexOf(v, from))) {
            this.markText({line: line, ch: idx}, {line: line, ch: idx + v.length}, v, 'cm-field');
            from = idx + v.length;
          }
        });
      }
    },
  },
};
</script>

<style lang="less" scoped>
.picker {
  height: 525px;
  text-align: left;
  width: 50%;
  margin: 0 auto;
  .code-edit {
    height: 240px;
    border-radius: 6px;
    border: 1px solid #e8e9eb;
  }
}
.top-title {
  background-color: #fafafa;
  height: 30px;
  vertical-align: center;
  line-height: 30px;
  padding-left: 10px;
  border-radius: 4px 4px 0 0;
  border-bottom: none;
}
/deep/ .CodeMirror {
  height: 200px !important;
  /*表单变量样式*/
  .cm-field {
    background: #007bff;
    padding: 3px 5px;
    border-radius: 3px;
    color: #fff;
    margin: 0 1px;
  }
  /*函数样式*/
  .cm-func {
    font-weight: bold;
    color: #ae4597;
    line-height: 14px;
    margin: 0 1px;
    padding: 0 2px;
  }
  .CodeMirror-scroll {
    width: 100%;
  }
}

</style>


http://www.niftyadmin.cn/n/4991346.html

相关文章

C语言每日一练---Day(14)

本专栏为c语言练习专栏&#xff0c;适合刚刚学完c语言的初学者。本专栏每天会不定时更新&#xff0c;通过每天练习&#xff0c;进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字&#xff1a;统计每个月兔子的总数 数列的和 &#x1f493;博主csdn个人主页&#x…

文件查找find,locate

非实时查找(数据库查找)&#xff1a;locate locate特点: 查找速度快模糊查找非实时查找搜索的是文件的全路径&#xff0c;不仅仅是文件名 locate用法 -i 不区分大小写的搜索 -n N 只列举前N个匹配项目 -r 使用基本正则表达式 搜索名称或路径中包含“conf"的文件 loca…

第三课:C++实现PDF去水印

PDF去水印是一项非常复杂的任务,需要一定的计算机图形学知识和技术,也需要使用到一些专业的工具库。以下是一种可能的实现方法: 首先,需要将PDF文件解析成一系列图形元素,包括文字、矢量图形等。可以使用开源库Poppler或MuPDF来解析PDF文件。 接下来,需要判断PDF文件是否…

【2023年下半年Java开发行情预测】

2023年下半年Java开发行情预测&#xff0c;需要考虑多种因素&#xff0c;包括市场需求、技术发展趋势、人才供需关系等。以下是我对Java开发行情的一些预测&#xff1a; 市场需求将继续保持增长&#xff1a; 随着数字化转型的加速&#xff0c;许多企业需要将业务迁移到云端&…

【go】异步任务解决方案Asynq实战

文章目录 一.Asynq介绍二.所需工具三.代码示例四.Reference 一.Asynq介绍 Asynq 是一个 Go 库&#xff0c;一个高效的分布式任务队列。 Asynq 工作原理&#xff1a; 客户端&#xff08;生产者&#xff09;将任务放入队列服务器&#xff08;消费者&#xff09;从队列中拉出任…

【无标题CAdUiPaletteSet】

#pragma once #include "TunnelSectionPalette.h"class CTunnelSectionPaletteSet : public CAdUiPaletteSet {DECLARE_DYNAMIC(CTunnelSectionPaletteSet)public:

Spring Boot多数据源配置运行报错:No operations allowed after connection closed连接异常的解决

上一篇文章我们讲了如何配置多数据源&#xff0c;但是配置在使用一段时间之后&#xff0c;查询数据库会发生报错&#xff1a;No operations allowed after connection closed。 一、问题原因&#xff1a; 经过排查发现是因为MySQL5.0以后针对超长时间DB连接做了一个处理&#…

链表形式队列

&#x1f308;队列相关概念 1.储存了数据的节点从一端&#xff08;队尾&#xff09;进入队列&#xff08;入队尾插&#xff09;&#xff0c;从另一端&#xff08;队头&#xff09;出队列&#xff08;出队头删&#xff09;&#xff0c;先进先出。进行插入操作的一端称为队尾&am…