时光有伱记忆成花

时光有伱记忆成花

效果图

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

 安装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>
09-02 04:35