CodeMirror 创建标签计算编辑器

8 篇文章 0 订阅
1 篇文章 0 订阅

         在日常开发中对于一些数据计算场景可能会遇到标签计算的需求,下面关于如何使用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 的使用即可。

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

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codemirror一个强大的开源文本编辑器库,它提供了丰富的功能和灵活的扩展性。要实现富文本编辑器,你可以结合 Codemirror 和其他工具或库来完成。 下面是一些步骤来使用 Codemirror 实现富文本编辑器: 1. 引入 Codemirror 库:在你的 HTML 文件中引入 Codemirror 的 CSS 和 JavaScript 文件。你可以从官方网站下载最新版本的文件,或者使用 CDN 引入。 2. 创建文本编辑器容器:在 HTML 中创建一个用于显示编辑器的容器元素,比如 `<div>` 元素。 3. 初始化 Codemirror 编辑器:在 JavaScript 中,使用 `CodeMirror()` 构造函数初始化编辑器。传入编辑器容器的 DOM 元素作为第一个参数,并且可以配置一些选项来自定义编辑器的外观和行为。 4. 配置选项:你可以使用一些选项来配置编辑器的样式、语言模式、插件等。比如,你可以通过设置 `mode` 选项来指定编辑器的语言模式(如 JavaScript、HTML 等),还可以使用各种插件来添加额外的功能。 5. 处理富文本内容:Codemirror一个代码编辑器,它默认处理纯文本内容。如果你要实现富文本编辑器,你需要将 Codemirror 与富文本内容的解析和渲染库结合使用。比如,你可以使用像 `Quill.js` 或 `TinyMCE` 这样的富文本编辑器库来处理富文本内容,并在需要时将其与 Codemirror 进行同步。 6. 添加事件处理:你可以通过监听编辑器的事件来处理用户的输入和其他交互操作。比如,你可以监听 `change` 事件来捕获编辑器内容的变化,并执行相应的操作。 以上是一个基本的实现富文本编辑器的步骤。具体的实现方式可能因你使用的框架或库而有所不同。你可以根据你的需求,进一步自定义编辑器的功能和样式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值