0


分享一个vue2的代码高亮编辑器[email protected]

一、简介

vue-codemirror是我最近项目中使用的一款代码在线编辑器,支持语言范围广、简单、易配置。

"vue-codemirror": "^4.0.6",

二、使用场景

第一种作为标签使用

第二种写sql也是没问题的,还支持配置关键字提示

三、安装方式(根据自己的使用习惯来,)

npm install -S vue-codemirror@4.0.6

yarn add vue-codemirror@4.0.6

四、项目中使用

首先引入以下两项

import { codemirror } from "vue-codemirror";

import "codemirror/lib/codemirror.css";

将codemirror在components中进行注册,然后在代码中使用

<codemirror
  ref="codeEditor"
  v-model="nameStr"
  :options="cmOptions"
  @input="codeMirrorChange"
></codemirror>

一部分配置项

cmOptions: {
        // 语言及语法模式
        mode: "text/x-sparksql",
        // 主题
        theme: "idea",
        // 显示函数
        line: true,
        lineNumbers: false,
        // 软换行
        lineWrapping: true,
        // tab宽度
        tabSize: 4,
        cursorHeight: 1, //光标高度,默认是1
      },

五、整体代码

<template>
  <div class="codeEditor">
    <div class="picker">
      <div class="ul-box">
        <el-input
          placeholder="请输入指标名称"
          v-model="dataName"
          clearable
          @input="filterIndex"
          @clear="filterIndex"
        >
          <i slot="prefix" class="el-input__icon el-icon-search"></i>
        </el-input>
        <ul>
          <li
            v-for="item in dataOpts"
            :key="item.id"
            @click="insertContent(item, 'variable')"
          >
            {{ item.name }}
          </li>
        </ul>
      </div>

      <div class="code-edit">
        <div class="top-title">公式</div>

        <codemirror
          ref="codeEditor"
          v-model="nameStr"
          :options="cmOptions"
          @input="codeMirrorChange"
        ></codemirror>
        <div class="code-btn">
          <el-button size="mini" @click="clearExp">清除 </el-button>
          <el-button size="mini" @click="checkExp"
            >公式检验<i v-if="checkStaus == 1" class="el-icon-loading"></i>
            <i
              v-if="checkStaus == 2"
              :class="
                checkFlag ? 'el-icon-circle-check' : 'el-icon-circle-close'
              "
              :title="checkFlag ? '检验成功' : '检验失败'"
            ></i>
          </el-button>
        </div>
      </div>
    </div>
    <div class="editor-btn">
      <el-button size="small" type="info" plain @click="cancelExp"
        >取消
      </el-button>
      <el-button
        size="small"
        type="primary"
        :disabled="!checkFlag"
        @click="sureExp"
        >确定
      </el-button>
    </div>
  </div>
</template>

<script>
// import { listByPage, checkExpression } from "@/api/indexSet";

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

export default {
  name: "",
  props: {
    detailInfo: {
      type: Object,
      default: () => {
        return {
          // nameStr,
          // codeStr,
        };
      },
    },
  },
  components: {
    codemirror,
  },
  data() {
    return {
      dataName: "",
      cmOptions: {
        // 语言及语法模式
        mode: "text/x-sparksql",
        // 主题
        theme: "idea",
        // 显示函数
        line: true,
        lineNumbers: false,
        // 软换行
        lineWrapping: true,
        // tab宽度
        tabSize: 4,
        cursorHeight: 1, //光标高度,默认是1
      },
      lang: "x-sparksql",
      nameStr: "",
      codeStr: "",
      codeList: [],
      nameList: [],
      dataOpts: [],
      initDataOpts: [],
      checkFlag: false,
      checkStaus: "",
      timer: null,
    };
  },
  computed: {
    editor() {
      return this.$refs.codeEditor.codemirror;
    },
  },
  watch: {
    nameStr: {
      handler(val) {
        if (!val) {
          this.codeStr = '';
          this.codeList = [];
          this.nameList = [];
          return;
        }
        console.time("换算时间");
        let str = val.match(/\[([\s\S]*?)\]/g);
        let res = str.toString().replace(/\[/g, "").replace(/\]/g, "");
        let arr = res.split(",");
        let codeStr = val;
        let codeList = [];
        let nameList = [];
        arr.forEach((e) => {
          let obj = this.initDataOpts.find((o) => o.name === e);
          codeList.push(obj.id);
          nameList.push(obj.name);
          codeStr = codeStr.replace(
            new RegExp(`\\[${e}\\]`, "g"),
            `[${obj.id}]`
          );
        });
        this.codeStr = codeStr;
        this.codeList = codeList;
        this.nameList = nameList;
        console.timeEnd("换算时间");
      },
      deep: true,
    },
  },
  created() {},
  async mounted() {
    await this.getDataOpts();
    this.focus(this.nameStr);
    this.autoMarkText();
  },
  methods: {
    filterIndex(val) {
      if (this.timer) {
        clearTimeout(this.timer);
      }
      this.timer = setTimeout(() => {
        if(val) {
          this.dataOpts = this.initDataOpts.filter((e) => e.name.includes(val));
        } else {
          this.dataOpts = JSON.parse(JSON.stringify(this.initDataOpts))
        }
        
      }, 500);
    },
    async getDataOpts() {
      let res = await listByPage({ type: 1 }, 1, 1000);
      this.dataOpts = res.data.listObject;
      this.initDataOpts = res.data.listObject;
      return true;
    },
    clearExp() {
      this.nameStr = "";
    },
    async checkExp() {
      this.checkStaus = 1;
      if (!this.nameStr) {
        setTimeout(() => {
          this.checkStaus = 2;
          this.checkFlag = false
        }, 500);
        return;
      }
      let data = {
        expressionVO: {
          nameStr: this.nameStr,
          codeStr: this.codeStr,
          codeList: this.codeList,
          nameList: this.nameList,
        },
        ids: this.codeList.join(","),
      };
      try {
        await checkExpression(data);
        this.checkStaus = 2;
        this.checkFlag = true;
      } catch (error) {
        this.checkStaus = 2;
        this.checkFlag = false
      }
    },
    cancelExp() {
      this.checkStaus = ''
      this.$emit("cancelExp");
    },
    sureExp() {
      this.$emit(
        "sureExp",
        this.nameStr,
        this.codeStr,
        this.codeList,
        this.nameList
      );
      this.checkStaus = ''
    },
    codeMirrorChange() {
      //获取 editor 的内容
      this.$nextTick(() => {
        this.autoMark()
      })
    },
    addFormula(content, type) {
      this.insertContent(content, type);
    },
    /**
     * editor 中的对内容进行处理
     * @param item
     * @param type variable | func,variable为表单变量,需标记,func 为函数,也需要做标记
     */
    insertContent(item, type) {
      const from = this.editor.getCursor();
      if (type === "variable") {
        this.editor.replaceSelection(`[${item.name}]`);
        const to = this.editor.getCursor();
        this.markText(from, to, `[${item.name}]`, "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() {
      this.$nextTick(() => {
        if (this.nameStr) {
          this.autoMark(this.nameStr);
          this.focus(this.nameStr);
        }
      });
    },
    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 _;
        });
        // 标记表单变量,这应该是动态获取,自行替换即可
        this.nameList.forEach((v) => {
          let from = 0;
          let idx = -1;
          while (~(idx = content.indexOf(v, from))) {
            this.markText(
              { line: line, ch: idx - 1 },
              { line: line, ch: idx + v.length + 1 },
              `[${v}]`,
              "cm-field"
            );
            from = idx + v.length;
          }
        });
      }
    },
  },
};
</script>
<style lang="less" scoped>
.codeEditor {
}

.picker {
  //   height: 525px;
  text-align: left;
  //   width: 50%;
  //   margin: 0 auto;
  display: flex;
  .ul-box {
    width: 300px;
    height: 420px;
    margin-right: 20px;
    .el-input {
      width: 100%;
      margin-bottom: 15px;
      //   margin-top: 10px;
      ::v-deep .el-input__inner {
        border-color: #dcdfe6 !important;
      }
    }

    ul {
      padding: 10px 0px;
      border-radius: 5px;
      border: 1px solid #efefef;
      overflow: auto;
      height: 369px;
    }
    li {
      line-height: 28px;
      padding: 0 20px;
      cursor: pointer;
    }
  }
  .code-edit {
    flex: 1;
    height: 420px;
    border-radius: 6px;
    border: 1px solid #e8e9eb;
    ::v-deep .CodeMirror {
      height: 350px !important;
    }
    .code-btn {
      margin-top: 5px;
      text-align: right;
      padding-right: 10px;
      // border-top: 1px solid #efefef;
      ::v-deep .el-icon-circle-close{
        color: rgb(241, 67, 67);
        margin-left: 5px;
      }
    }
  }
}
.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 {
  /*表单变量样式*/
  .cm-field {
    // background: #007bff;
    // padding: 3px 5px;
    // border-radius: 3px;
    color: #179e34;
    margin: 0 1px;
  }
  /*函数样式*/
  .cm-func {
    font-weight: bold;
    color: #ae4597;
    line-height: 14px;
    margin: 0 1px;
    padding: 0 2px;
  }
  .CodeMirror-scroll {
    width: 100%;
  }
}
.editor-btn {
  margin-top: 15px;
  text-align: right;
}
</style>
标签: vue.js 编辑器 前端

本文转载自: https://blog.csdn.net/u014197593/article/details/137009769
版权归原作者 一个不太专业的码农 所有, 如有侵权,请联系我们删除。

“分享一个vue2的代码高亮编辑器[email protected]”的评论:

还没有评论