分享一个vue2的代码高亮编辑器vue-codemirror@4.0.6

一、简介 

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>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vue-codemirror一个基于Vue.js代码编辑器组件,提供了一个用户友好的界面和丰富的功能来编辑各种编程语言的代码。引用中的内容是Vue-codemirror组件的一些属性和配置选项。 其中,value属性用于设置编辑器的初始内容,可以是代码字符串或者是从服务器加载的代码文件。这样可以在编辑器中显示已有的代码。 Mode属性用于设置编译器的编程语言关联内容,通过引入对应的模块或包,使得编辑器能够识别和高亮显示特定编程语言的语法。 Theme属性用于设置编辑器的主题,可以选择不同的主题样式来满足用户的个性化需求。 tabSize属性用于设置tab的空格宽度,可以根据用户的喜好和项目要求来调整。 lineNumbers属性用于决定是否在编辑器中显示行号,方便用户进行代码的定位和调试。 smartIndent属性用于控制自动缩进的开关,当该选项打开时,编辑器会根据上一行的缩进自动调整下一行的缩进。 indentUnit属性用于设置缩进的单位,可以是空格或者制表符,根据项目的要求来进行设置。 keyMap属性用于设置快捷键,可以自定义或选择预设的快捷键方案,以提高代码编辑的效率。 通过配置这些属性和选项,可以使得vue-codemirror代码编辑器满足不同开发需求,并提供良好的编码体验。<span class="em">1</span> #### 引用[.reference_title] - *1* [vue codemirror 代码编辑器](https://blog.csdn.net/qq_42181155/article/details/121253626)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值