CodeMirror 创建标签计算编辑器

         在日常开发中对于一些数据计算场景可能会遇到标签计算的需求,下面关于如何使用CodeMirror实现标签计算编辑功能。

1,结果图

2,主体代码逻辑

大家只需要复制粘贴主要codeMirror使用逻辑即可


<template>
  <el-dialog
    ref="dialogRef"
    :model-value="visible"
    width="800px"
    :close-on-press-escape="false"
    destroy-on-close
    append-to-body
    @close="
      () => {
        $emit('update:visible', false);
      }
    "
  >
    <template #title>
      <span> 编辑表达式 </span>
    </template>
      <!-- 左侧无用dom元素已删除 -->
      <div class="content__right">
        <div class="symbol-group">
          <div v-for="item in symbolList" :key="item.code" class="symbol-item" @click="handleSymbolClick(item)">
            {{ item.name }}
          </div>
        </div>
        <!-- 代码编辑器 -->
        <textarea
          ref="codeEditorContainerRef"
          v-model="currentCodeInEditor"
          class="editor"
        />
      </div>
    </div>

    <template #footer>
      <div class="dialog-button-box">
        <el-button
          size="small"
          @click="
            () => {
              $emit('update:visible', false);
            }
          "
        >
          取消
        </el-button>
        <el-button size="small" type="primary" @click="handleOk">
          确定
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, watch, ref, onMounted, nextTick } from 'vue';
import { InfoFilled, Search } from '@element-plus/icons';
import { TreeNodeData } from 'element-plus/es/el-tree/src/tree.type.d';
// 引入代码编辑器核心配置包
import * as CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';

// 引入代码编辑器主题样式
import 'codemirror/theme/base16-light.css';
import 'codemirror/theme/ambiance.css';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/theme/monokai.css';
import 'codemirror/theme/material.css';
import 'codemirror/theme/dracula.css';
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/mode/javascript/javascript';

// 引入代码编辑器常用语言包
require('codemirror/addon/edit/matchbrackets');
require('codemirror/addon/selection/active-line');
require('codemirror/mode/sql/sql');
require('codemirror/addon/hint/show-hint');
require('codemirror/addon/hint/sql-hint');
require('codemirror/keymap/sublime');

// 引入代码折叠文件
require('codemirror/addon/fold/foldcode');
require('codemirror/addon/fold/foldgutter');
require('codemirror/addon/fold/brace-fold');
require('codemirror/addon/fold/xml-fold');
require('codemirror/addon/fold/indent-fold');
require('codemirror/addon/fold/markdown-fold');
require('codemirror/addon/fold/comment-fold');


export default defineComponent({
  name: 'RemarksDialog',
  components: {
    
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    data: {
      type: String,
      default: '',
    },
  },
  emits: ['update:visible', 'save'],
  setup(props, { emit }) {
    const dialogRef = ref();
    const state = reactive({
      // 符号列表
      symbolList: [
        {
          id: 'plus',
          code: 'plus',
          name: '+',
          type: 'operator',
        },
        {
          id: 'minus',
          code: 'minus',
          name: '-',
          type: 'operator',
        },
        {
          id: 'multiply',
          code: 'multiply',
          name: '*',
          type: 'operator',
        },
        {
          id: 'exception',
          code: 'exception',
          name: '/',
          type: 'operator',
        },
        {
          id: 'leftBrackets',
          code: 'leftBrackets',
          name: '(',
          type: 'operator',
        },
        {
          id: 'rightBrackets',
          code: 'rightBrackets',
          name: ')',
          type: 'operator',
        },
      ] as SymbolItem[],
    });

    // 代码编辑器容器实例
    const codeEditorContainerRef = ref<HTMLElement | null>();
    // 代码编辑器
    let editor : TreeNodeData | null;

    // 编辑器当前所用编程语言
    const currentLanguage = ref('javascript');
    // 编辑器当前主题
    const currentTheme = ref('base16-light');
    // 编辑器当前展示的代码
    const currentCodeInEditor = ref();

    // 获取表达式的元素集合
    const getCalcResult = (): SymbolItem[] => {
      const temp: any[] = editor?.getValue()
        .split('$');
      // 清除最后一个空格元素
      temp.pop();
      // 循环生成最后的集合
      return temp
        .map((item: string) => state.calculationIdMap[item])
        .filter((item) => !!item);
    };


    /**
     * @description: 创建标签
     * @return {*}
     */
    const makeLabel = (mark: any) => {
      const spanDom = document.createElement('span');
      const label = mark.variable;
      spanDom.title = label;
      spanDom.innerText = label;
      spanDom.classList.add('textarea-tag');
      spanDom.dataset.variable = mark.variable;
      editor?.markText(mark.start, mark.end, {
        replacedWith: spanDom, // 将特定位置的文本替换成给定的节点元素,必须是行元素,不能是块元素
        atomic: true, // 原子化,会把节点元素当成一个整体,光标不会进入其中
      });
    };


    /**
     * @description: 插入标签
     * @return {*}
     */
    const insertLabel = (content: any, isCalcDim: boolean) => {
      if (!content) return;
      const cursor = editor?.getCursor();
      editor?.replaceSelection(`${content.code}$`);
      makeLabel({
        start: cursor,
        end: editor?.getCursor(), // 获取自定义标签插入之后的光标对象
        variable: content.name,
      });
      editor?.setCursor(editor?.getCursor());
      editor?.focus();
    };

    /**
     * 初始化代码编辑器
     */
    const initEditor = () => {
      nextTick(() => {
        if (codeEditorContainerRef.value) {
          editor = CodeMirror.fromTextArea(codeEditorContainerRef.value, {
          // 编辑器语言的模式
            mode: currentLanguage.value,
            // 编辑器主题风格
            theme: currentTheme.value,
            // 缩进的时候,是否把前面的 N*tab 大小的空间,转化为 N个tab 字符
            indentWithTabs: true,
            // 是否使用 mode 提供的上下文的缩进
            smartIndent: true,
            // 编辑器左侧是否显示行号
            lineNumbers: true,
            // 括号匹配
            matchBrackets: true,
            // 初始化时是否自动获得焦点
            autofocus: true,
            // 代码自动换行
            lineWrapping: true,
            // 代码块折叠
            foldGutter: true,
            // 只读
            readOnly: false,
            // 代码块折叠样式
            gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
            // 自定义快捷键
            extraKeys: { Ctrl: 'autocomplete' },
            // 自定义提示选项
            hintOptions: {
              tables: {
                users: ['name', 'score', 'birthDate'],
                countries: ['name', 'population', 'size'],
              },
            },
          });
          // 公式回显
          if (props.data) {
            const dataArray = JSON.parse(props.data);
            dataArray.forEach((item: any) => {
              insertLabel(item, false);
              state.calculationIdMap[item.code] = item;
            });
            // 重新计算时间维度和可用维度
            setTimeout(() => {
              // 重新计算时间维度和其他可用维度
              resetCurrentDateDimension();
              resetCurrentOtherDimension();
            }, 500);
          }
        }
      });
    };


    /**
     * @description: 符号点击触发方法
     * @param {SymbolItem} data
     * @return {*}
     */
    const handleSymbolClick = (data: SymbolItem) => {
      insertLabel(data, false);
      state.calculationIdMap[data.code] = data;
    };


    watch(
      () => props.visible,
      async (newVal) => {
        if (newVal) {
          initEditor();
          await getIndicatorList();
        } else {
          state.currentOtherDimension = [];
          state.currentDateDimension = {} as any;
        }
      },
    );

    return {
      ...toRefs(state),
      dialogRef,
      Search,
      codeEditorContainerRef,
      currentCodeInEditor,
      handleSymbolClick,
    };
  },
});
</script>

<style lang="scss" scoped>

</style>

大家只需要关注codeMirror插件的引入以及相关api 的使用即可。

未解决的问题:在点击生成标签只有,不能通过鼠标点击直接移动光标位置,只能通过方向键移动光标位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/670379.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

7.2 Go 使用error类型

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

godot.bk

1.搜索godot国内镜像&#xff0c;直接安装&#xff0c;mono是csharp版本 2.直接解压&#xff0c;50m&#xff0c;无需安装&#xff0c;直接运行 3.godot里分为场景&#xff0c;节点 主场景用control场景&#xff0c;下面挂textureact放背景图片&#xff0c;右键实例化子场景把…

自然语言处理(NLP)—— 置信度(Confidence)

1. 置信度&#xff08;Confidence&#xff09;的概念 置信度&#xff08;Confidence&#xff09;在机器学习和统计中通常指一个模型对其做出的预测是正确的确信程度。在分类任务中&#xff0c;置信度通常由模型赋予特定类别的概率值来表示。例如&#xff0c;在文本分类或实体识…

外界访问docker服务失败

各位i大佬请问一下&#xff1a;我容器起了&#xff0c;但是外网访问不了目标机器的9090端口。 我检查了&#xff1a;1.本机的防火墙已关闭&#xff0c; 2.目标机器的9090端口显示正在被docker监听。 3.外网可以访问目标机器。 4.docker日志&#xff0c;未显示服务报错。 5…

07.与jenkins集成实现cicd

7.与jenkins集成实现ci/cd ip地址服务内存192.168.111.11kube-apiserver 80801G192.168.111.13k8s-node22G192.168.111.14jenkins(tomcat jdk) 8080 kubelet docker1G192.168.111.15gitlab 8080,80 docker2G 通过jenkins一键操作实现发布服务&#xff0c;jenkins对接k8s …

【前缀和】42. 接雨水

本文涉及知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&am…

【PPT】根据字体大小自动缩放文本框大小

【PPT】根据字体大小自动缩放文本框大小 一般我们新建文本框输入文字后&#xff0c;文本框的大小是不会自动缩放的&#xff0c;是根据你一开始拖动的尺寸固定的 你可以设置文本框的长度随着文字的变化而自动调整。这样&#xff0c;无论你输入多少文字&#xff0c;文本框都会自…

FFmpeg开发笔记(三十三)分析ZLMediaKit对H.264流的插帧操作

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“3.4.3 把原始的H264文件封装为MP4格式”介绍了如何把H.264裸流封装为MP4文件。那么在网络上传输的H.264裸流是怎样被接收端获取视频格式的呢&#xff1f;前文指出H.264流必定以“SPS帧→PPS帧→IDR帧”开头&#x…

深入JVM:全面解析GC调优

文章目录 深入JVM&#xff1a;全面解析GC调优一、序言二、GC调优指标三、GC在线监控1、Jstat工具2、VisualVM工具 四、GC日志分析1、收集GC日志2、GCViewer工具3、GCeasy工具 五、GC问题调优1、调整JVM内存大小&#xff08;1&#xff09;调整堆内存大小及比例&#xff08;2&…

ChatGPT-4o 有何特别之处?

文章目录 多模态输入&#xff0c;多模态输出之前的模型和现在模型对比 大家已经知道&#xff0c;OpenAI 在 GPT-4 发布一年多后终于推出了一个新模型。它仍然是 GPT-4 的一个变体&#xff0c;但具有前所未见的多模态功能。 有趣的是&#xff0c;它包括实时视频处理等强大功能&…

疫情物资捐赠和分配系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;机构管理&#xff0c;用户管理&#xff0c;发放管理&#xff0c;物资管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;物资论坛&#xff0c;公告信息…

7.1 Go 错误的概念

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Python:由b站临时短链接获取到永久链接(去除分享中的杂项)

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…

LabVIEW在高校电力电子实验中的应用

概述&#xff1a;本文介绍了如何利用LabVIEW优化高校电力电子实验&#xff0c;通过图形化编程实现参数调节、实时数据监控与存储&#xff0c;并与Simulink联动&#xff0c;提高实验效率和数据处理能力。 需求背景高校实验室在进行电机拖动和电力电子实验时&#xff0c;通常使用…

MongoDB CRUD操作:插入文档

MongoDB CRUD操作&#xff1a;插入文档 文章目录 MongoDB CRUD操作&#xff1a;插入文档使用MongoDB Atlas UI插入文档插入单个文档插入多个文档插入行为自动创建集合_id字段原子性写确认 在MongoDB中插入文档的集中方式&#xff1a; 使用编程语言提供的驱动程序&#xff0c;在…

Table表格组件不请求接口,实现表格里某条数据的本地编辑功能(Vue3+ArcoDesign)

【背景】 在 Vue3 ArcoDesign项目中&#xff0c;使用ArcoDesign-Table表格组件不请求接口&#xff0c;实现表格里某条数据的本地编辑功能。最后统一通过接口发送数据。 【步骤】 1. 在表格每条数据列后添加一个“编辑”按钮&#xff0c;点击该按钮弹出一个对话框&#xff0c…

flink 作业报日志类冲突的解决方案

文章目录 背景思考初步解决方案深入思考下终极解决方案总结 背景 实时作业在页面提交任务后&#xff0c;报NoSuchMethodException 方法&#xff0c;看了下是关于log4j的&#xff0c;首先是作业升级了很多依赖的版本&#xff0c;其次flink 也升级 到了1.19版本 思考 打的Jar有…

计算一个3x3矩阵对角线和其它两条线的元素之和

计算一个3x3矩阵对角线和其它两条线的元素之和 #include <stdio.h> int main () { int d0,b0,s,i,j; int a[3][3]{1,2,3,4,5,6,7,8,9}; for(i0,j2;i<3;i,j--) dda[i][i]a[i][j]; for(i0,j0;i<3;) {bba[i][j]a[i][j2]; ii2;} sdb; printf("d%d\nb%d\ns%d\n&qu…

远程继电器模块实现(nodemcu D1 + 继电器)

前言 接下来将实现一个远程继电器&#xff0c;实时远程控制和查询的开关状态。用 5v 直流电控制 220v 交流电。 硬件上&#xff1a; 使用 nodemcu D1 和 JQC-3FF-S-Z 继电器。 软件上&#xff1a; 使用 nodejs 作为服务端&#xff0c;和 html 作为客户端。 在开始之前在电脑…

数模混合芯片设计中的修调技术是什么?

一、修调目的 数模混合芯片需要修调技术主要是因为以下几个原因&#xff1a; 工艺偏差&#xff08;Process Variations&#xff09;&#xff1a; 半导体制造过程中存在不可避免的工艺偏差&#xff0c;如晶体管尺寸、阈值电压、电阻和电容值等&#xff0c;这些参数的实际值与…