vue实现公式编辑器组件

实现方式一

1、效果图

2、实现代码 

组件弹框实现 样式自己调整  公式的数字与汉字元素、符号 建立元素表 动态获取

完整代码(calculate.vue)

<template>
    <div id="formulaPage">
      <div
        ref="formulaView"
        class="formulaView"
        contentEditable="false"
        @click="recordPosition"
        @keyup="editEnter($event)"
        @copy="copy($event)"
        @paste="paste($event)"
      />
      <div class="infomationContent">
        <div class="infomationContent-leftFlexbox">
          <div class="tab">
            <ul style="width: 200px">
              <li
                v-for="(v, i) in Num"
                :key="i"
                class="numberClass"
                :style="{ background: v.backgroundColor }"
                @click="addItem($event, 2, v, false)"
              >
                {{ v.displayValue }}
              </li>
            </ul>
          </div>
          <div class="tab">
            <ul style="width: 500px">
              <li
                v-for="(v, i) in customType"
                :key="i"
                class="typeClass"
                :style="{ background: v.backgroundColor }"
                :class="{ noclick: v.isFlag }"
                @click="addItem($event, 2, v, v.isFlag)"
              >
                {{ v.displayValue }}
              </li>
            </ul>
          </div>
          <div class="tab">
            <ul style="width: 200px">
              <li
                v-for="(v, i) in Symbol"
                :key="i"
                class="symbolClass"
                :style="{ background: v.backgroundColor }"
                @click="addItem($event, 2, v, false)"
              >
                {{ v.displayValue }}
              </li>
            </ul>
          </div>
        </div>
        <div class="infomationContent-rightBtnbox">
          <div class="imgboxinfo" style="margin-bottom: 32px">
            <img src="@/assets/images/rolback.png" alt="" style="width: 40px; height: 40px" @click="deleteHumerText" />
          </div>
          <div class="imgboxinfo">
            <img src="@/assets/images/calSave.png" alt="" style="width: 40px; height: 40px" @click="onSaveformulaEvent" />
          </div>
        </div>
      </div>
   
      <!-- <div class="footerComtent">
        <el-button type="primary" style="width: 200px; height: 30px" @click="onSaveformulaEvent">保存</el-button>
      </div> -->
      <!-- <button @click="parsingFormula('(长+宽+高)*2')">反向解析公式</button> -->
      <!-- <button @click="deleteHumerText()">删除</button> -->
    </div>
  </template>
   
  <script>
   
  export default {
    name: 'FormulaPage',
    props: {
      content: { type: String, default: '' },
      recoverdate: {
        type: Array,
        default: () => []
      },
      domflag: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        // 权限分类 元素分类不可用集合
        btnsRuleArray: {
          offer: ['thickness', 'nailmouth', 'bellsocket', 'gramweight'], // 报价
          weight: ['thickness', 'unitprice'], // 重量
          areavolume: ['gramweight', 'unitprice'] // 体积、面积、纸宽、纸长
        },
        // 公式字符串
        formulaStr: '',
        // 公式编辑器最后光标位置
        formulaLastRange: null,
        Num: [{
          "displayValue":"1",
          "saveValue":"1"
        },{
          "displayValue":"2",
          "saveValue":"2"
        },{
          "displayValue":"3",
          "saveValue":"3"
        },{
          "displayValue":"4",
          "saveValue":"4"
        },{
          "displayValue":"5",
          "saveValue":"5"
        },{
          "displayValue":"6",
          "saveValue":"6"
        },{
          "displayValue":"7",
          "saveValue":"7"
        },{
          "displayValue":"8",
          "saveValue":"8"
        },{
          "displayValue":"9",
          "saveValue":"9"
        },{
          "displayValue":"0",
          "saveValue":"0"
        },{
          "displayValue":".",
          "saveValue":"."
        }],
        Symbol: [
        {
          "displayValue":"+",
          "saveValue":"+"
        },{
          "displayValue":"-",
          "saveValue":"-"
        },{
          "displayValue":"x",
          "saveValue":"*"
        },{
          "displayValue":"÷",
          "saveValue":"/"
        },{
          "displayValue":"(",
          "saveValue":"("
        },{
          "displayValue":")",
          "saveValue":")"
        },{
          "displayValue":"{",
          "saveValue":"{"
        },{
          "displayValue":"}",
          "saveValue":"}"
        },
        ],
        customType: [{
          "displayValue":"上报产量",
          "saveValue":"report_production"
        },{
          "displayValue":"实际产量",
          "saveValue":"reality_production"
        },{
          "displayValue":"红矿",
          "saveValue":"red_ore"
        },{
          "displayValue":"青堆",
          "saveValue":"black_stack"
        },{
          "displayValue":"红堆",
          "saveValue":"red_stack"
        },{
          "displayValue":"煤存",
          "saveValue":"coal_storage"
        },{
          "displayValue":"槽存",
          "saveValue":"slot_storage"
        },{
          "displayValue":"土耗",
          "saveValue":"soil_used"
        },{
          "displayValue":"土存",
          "saveValue":"soil_stock"
        },{
          "displayValue":"煤耗",
          "saveValue":"coal_used"
        },{
          "displayValue":"产量",
          "saveValue":"production"
        },{
          "displayValue":"用电量",
          "saveValue":"meter_used"
        }],
        backFormulaStrArray: [] // 按键值存储编辑器数据
      }
    },
    created() {
      this.backFormulaStrArray = []
   
      if (this.recoverdate) {
        this.backFormulaStrArray = this.recoverdate
        this.$nextTick(function () {
          this.parsingFormulaCustom(this.recoverdate)
        })
      }
   
    //   this.getList()
    },
    methods: {
      /** 查询所有公式元素 */
      getList() {
        listElement({ pageNum: 1, pageSize: 50 }).then(response => {
          response.rows.forEach(item => {
            item.isFlag = false
            if (this.domflag) {
              const newLegth = this.btnsRuleArray[this.domflag].filter(e => e == item.saveValue)
              if (newLegth.length > 0) {
                item.isFlag = true
              }
            }
          })
          const numberDate = response.rows
            .filter(e => {
              return e.elementType == 'number'
            })
            .sort((a, b) => {
              return a.order - b.order
            })
          const formulaElementDate = response.rows
            .filter(e => {
              return e.elementType == 'formulaElement'
            })
            .sort((a, b) => {
              return a.order - b.order
            })
          const symbolDate = response.rows
            .filter(e => {
              return e.elementType == 'symbol'
            })
            .sort((a, b) => {
              return a.order - b.order
            })
          this.Num = numberDate
          this.Symbol = symbolDate
          this.customType = formulaElementDate
        })
      },
      // 删除操作---从最后删除
      deleteHumerText() {
        if (this.backFormulaStrArray.length > 0) {
          this.backFormulaStrArray.splice(-1, 1)
          while (this.$refs.formulaView.firstChild) {
            this.$refs.formulaView.removeChild(this.$refs.formulaView.firstChild)
          }
          this.backFormulaStrArray.forEach(item => {
            const fd = document.createDocumentFragment()
            const empty = document.createTextNode(' ')
            const formulaEl = document.createTextNode(' ' + item.displayValue + ' ')
            fd.appendChild(empty)
            fd.appendChild(formulaEl)
            fd.appendChild(empty)
            this.$refs.formulaView.appendChild(fd)
   
            // 创建新的光标对象
            var range = document.createRange()
            // 光标对象的范围界定
            range.selectNodeContents(formulaEl)
            // 光标位置定位
            range.setStart(formulaEl, formulaEl.data.length - 1)
   
            // 使光标开始和光标结束重叠
            range.collapse(true)
            // 清除选定对象的所有光标对象
            window.getSelection().removeAllRanges()
            // 插入新的光标对象
            window.getSelection().addRange(range)
   
            // 保存新光标
            this.recordPosition()
          })
        }
        
      },
      // 保存数据 回调父组件
      onSaveformulaEvent() {
        const strParams = this.backFormulaStrArray.map(e => e.saveValue).join('')
        const strParamsValue = this.backFormulaStrArray.map(e => e.displayValue).join('')
   
        const newbackFormulaStrArray = []
        this.backFormulaStrArray.forEach(item => {
          const obj = {
            displayValue: item.displayValue,
            elementType: item.elementType,
            saveValue: item.saveValue
          }
   
          newbackFormulaStrArray.push(obj)
        })
   
        this.parsingFormula('')
        this.$emit('onChangeSuccess', strParams, strParamsValue, newbackFormulaStrArray)
        this.backFormulaStrArray = []
        console.log(strParams)
        console.log(strParamsValue)
        console.log(newbackFormulaStrArray)
        // const ifLegal1 = [...strParamsValue].reduce((a, i) => (i === '(' ? a + 1 : a - 1), 0)
      },
      isValidate(str) {
        const inArr = []
   
        const arr = str.split('')
   
        for (const s of arr) {
          if (s === '{' || s === '[' || s === '(') {
            // 入栈
            inArr.push(s)
          }
          if (s === '}' || s === ']' || s === ')') {
            let temp
            switch (s) {
              case '}':
                temp = '{'
                break
              case ']':
                temp = '['
                break
              case ')':
                temp = '('
                break
            }
            // 出栈
            const out = inArr.pop()
   
            if (temp !== out) {
              return false
            }
          }
        }
        return true
      },
      // 获取公式
      getFormula: function () {
        var nodes = this.$refs.formulaView.childNodes
        var str = ''
        for (let i = 0; i < nodes.length; i++) {
          var el = nodes[i]
          if (el.nodeName == 'SPAN') {
            // console.log(el);
            str += '#' + el.innerHTML.trim() + '#'
          } else {
            // console.log(el.data);
            str += el.data ? el.data.trim() : ''
          }
        }
        // console.log(str);
        this.formulaStr = str
      },
      // 点选时记录光标位置
      recordPosition: function () {
        // 保存最后光标点
        this.formulaLastRange = window.getSelection().getRangeAt(0)
      },
      // 添加字段 type 1 字段  2 公式
      addItem: function (e, type, itemRows, isusable) {
        if (isusable) {
          e.preventDefault()
          return false
        }
        if (this.backFormulaStrArray.length > 0) {
          if (itemRows.elementType == 'formulaElement' || itemRows.elementType == 'symbol') {
            // 检验连续相同两个元素不能重复 符号/元素
            if (this.backFormulaStrArray[this.backFormulaStrArray.length - 1].displayValue == itemRows.displayValue) {
              e.preventDefault()
              return false
            }
            // 检验不同元素连续两个不能是用一个类型
            if (
              this.backFormulaStrArray[this.backFormulaStrArray.length - 1].elementType == 'formulaElement' &&
              itemRows.elementType == 'formulaElement'
            ) {
              e.preventDefault()
              return false
            }
   
            if (
              this.backFormulaStrArray[this.backFormulaStrArray.length - 1].elementType == 'number' &&
              itemRows.elementType == 'formulaElement'
            ) {
              e.preventDefault()
              return false
            }
          }
          if (itemRows.elementType == 'number' && itemRows.saveValue == '.') {
            if (this.backFormulaStrArray[this.backFormulaStrArray.length - 1].displayValue == itemRows.displayValue) {
              e.preventDefault()
              return false
            }
          }
   
          //  this.backFormulaStrArray.forEach(item => {
          //         console.log(item.displayValue,itemRows.displayValue)
          // const reg = RegExp(`(${item.displayValue})\1`, 'g'))
          // console.log(strParamsValue.match(reg))
          // })
        }
   
        this.backFormulaStrArray.push(itemRows)
   
        const isValiStr = this.backFormulaStrArray.map(e => e.displayValue).join('')
        if (!this.isValidate(isValiStr)) {
          this.backFormulaStrArray.splice(-1, 1)
          e.preventDefault()
          return false
        }
   
        // 当前元素所有子节点
        var nodes = this.$refs.formulaView.childNodes
        // 当前子元素偏移量
        var offset = this.formulaLastRange && this.formulaLastRange.startOffset
        // 当前光标后的元素
        var nextEl = this.formulaLastRange && this.formulaLastRange.endContainer
   
        // 创建节点片段
        var fd = document.createDocumentFragment()
        // 创建字段节点  空白间隔节点  公式节点
        var spanEl = document.createElement('span')
        spanEl.setAttribute('contentEditable', false)
        // 标识为新添加元素 用于定位光标
        spanEl.setAttribute('new-el', true)
        spanEl.innerHTML = e.target.innerHTML
        var empty = document.createTextNode(' ')
        var formulaEl = document.createTextNode(' ' + e.target.innerHTML + ' ')
   
        // 区分文本节点替换 还是父节点插入
        if (nextEl && nextEl.className != 'formulaView') {
          // 获取文本节点内容
          var content = nextEl.data
          // 添加前段文本
          fd.appendChild(document.createTextNode(content.substr(0, offset) + ' '))
          fd.appendChild(type == 1 ? spanEl : formulaEl)
          // 添加后段文本
          fd.appendChild(document.createTextNode(' ' + content.substr(offset)))
          // 替换节点
          this.$refs.formulaView.replaceChild(fd, nextEl)
        } else {
          // 添加前段文本
          fd.appendChild(empty)
          fd.appendChild(type == 1 ? spanEl : formulaEl)
          fd.appendChild(empty)
   
          // 如果有偏移元素且不是最后节点  中间插入节点  最后添加节点
          if (nodes.length && nodes.length > offset) {
            this.$refs.formulaView.insertBefore(fd, nextEl && nextEl.className != 'formulaView' ? nextEl : nodes[offset])
          } else {
            this.$refs.formulaView.appendChild(fd)
          }
        }
   
        // 遍历光标偏移数据 删除标志
        var elOffSet = 0
        for (let i = 0; i < nodes.length; i++) {
          const el = nodes[i]
          // console.log(el,el.nodeName == 'SPAN'&&el.getAttribute('new-el'));
          if (el.nodeName == 'SPAN' && el.getAttribute('new-el')) {
            elOffSet = i
            el.removeAttribute('new-el')
          }
        }
   
        // 创建新的光标对象
        var range = document.createRange()
        // 光标对象的范围界定
        range.selectNodeContents(type == 1 ? this.$refs.formulaView : formulaEl)
        // 光标位置定位
        range.setStart(
          type == 1 ? this.$refs.formulaView : formulaEl,
          type == 1 ? elOffSet + 1 : formulaEl.data.length - 1
        )
   
        // 使光标开始和光标结束重叠
        range.collapse(true)
        // 清除选定对象的所有光标对象
        window.getSelection().removeAllRanges()
        // 插入新的光标对象
        window.getSelection().addRange(range)
   
        // 保存新光标
        this.recordPosition()
      },
      // 复制
      copy: function (e) {
        // 选中复制内容
        e.preventDefault()
        //
        var selContent = document.getSelection().toString().split('\n')[0]
        // 替换选中内容
        e.clipboardData.setData('text/plain', selContent)
      },
      // 输入回车
      editEnter: function (e) {
        e.preventDefault()
        if (e.keyCode == 13) {
          // 获取标签内容 并把多个换行替换成1个
          var content = this.$refs.formulaView.innerHTML.replace(/(<div><br><\/div>){2,2}/g, '<div><br></div>')
          // 记录是否第一行回车
          var divCount = this.$refs.formulaView.querySelectorAll('div')
          // var tE = this.$refs.formulaView.querySelect('div');
          // console.log(this.$refs.formulaView.childNodes);
          // console.log(this.$refs.formulaView.querySelectorAll("div"));
          // 获取当前元素内所有子节点
          var childNodes = this.$refs.formulaView.childNodes
          // 记录当前光标子节点位置
          var rangeIndex = 0
          for (let i = 0; i < childNodes.length; i++) {
            var one = childNodes[i]
            if (one.nodeName == 'DIV') {
              rangeIndex = i
            }
          }
          // 如果有替换则进行光标复位
          if (divCount.length >= 1) {
            // 替换回车插入的div标签
            content = content.replace(/<div>|<\/div>/g, function (word) {
              // console.log(word);
              if (word == '<div>') {
                // 如果是第一行不在替换br
                return divCount.length > 1 ? ' ' : ' <br>'
              } else if (word == '</div>') {
                return ' '
              }
            })
            // 更新替换内容,光标复位
            this.$refs.formulaView.innerHTML = content
            // 创建新的光标对象
            var range = document.createRange()
            // 光标对象的范围界定为新建的表情节点
            range.selectNodeContents(this.$refs.formulaView)
            // 光标位置定位在表情节点的最大长度
            range.setStart(this.$refs.formulaView, rangeIndex + (divCount.length > 1 ? 0 : 1))
            // 使光标开始和光标结束重叠
            range.collapse(true)
            // 清除选定对象的所有光标对象
            window.getSelection().removeAllRanges()
            // 插入新的光标对象
            window.getSelection().addRange(range)
          }
        }
        // 保存最后光标点
        this.formulaLastRange = window.getSelection().getRangeAt(0)
      },
      // 获取粘贴事件
      paste: function (e) {
        e.preventDefault()
        // var txt=e.clipboardData.getData();
        // console.log(e, e.clipboardData.getData());
        return ''
      },
      // 公式反向解析
      parsingFormula: function (formulaStr) {
        // 渲染视口
        var view = this.$refs.formulaView
        // 反向解析公式
        var str = formulaStr.replace(/#(.+?)#/g, function (word, $1) {
          // console.log(word,$1);
          return "<span contentEditable='false'>" + $1 + '</span>'
        })
   
        // console.log(str,fd.innerHTML);
        view.innerHTML = str
        // this.$refs.formulaView.appendChild(fd);
   
        // 创建新的光标对象
        var range = document.createRange()
        // 光标对象的范围界定为新建的表情节点
        range.selectNodeContents(view)
        // 光标位置定位在表情节点的最大长度
        range.setStart(view, view.childNodes.length)
   
        // 使光标开始和光标结束重叠
        range.collapse(true)
        // 清除选定对象的所有光标对象
        window.getSelection().removeAllRanges()
        // 插入新的光标对象
        window.getSelection().addRange(range)
   
        // 保存新光标
        this.recordPosition()
      },
      parsingFormulaCustom(arrayDatelist) {
        arrayDatelist.forEach(item => {
          // 当前元素所有子节点
          const nodes = this.$refs.formulaView.childNodes
          // 当前子元素偏移量
          const offset = this.formulaLastRange && this.formulaLastRange.startOffset
          // 当前光标后的元素
          const nextEl = this.formulaLastRange && this.formulaLastRange.endContainer
          const fd = document.createDocumentFragment()
          const empty = document.createTextNode(' ')
          const formulaEl = document.createTextNode(' ' + item.displayValue + ' ')
   
          if (nextEl && nextEl.className != 'formulaView') {
            var content = nextEl.data
            fd.appendChild(document.createTextNode(content.substr(0, offset) + ' '))
            fd.appendChild(formulaEl)
            fd.appendChild(document.createTextNode(' ' + content.substr(offset)))
            this.$refs.formulaView.replaceChild(fd, nextEl)
          } else {
            fd.appendChild(empty)
            fd.appendChild(formulaEl)
            fd.appendChild(empty)
            // 如果有偏移元素且不是最后节点  中间插入节点  最后添加节点
            if (nodes.length && nodes.length > offset) {
              this.$refs.formulaView.insertBefore(
                fd,
                nextEl && nextEl.className != 'formulaView' ? nextEl : nodes[offset]
              )
            } else {
              this.$refs.formulaView.appendChild(fd)
            }
          }
   
          // 创建新的光标对象
          var range = document.createRange()
          // 光标对象的范围界定
          range.selectNodeContents(formulaEl)
          // 光标位置定位
          range.setStart(formulaEl, formulaEl.data.length - 1)
   
          // 使光标开始和光标结束重叠
          range.collapse(true)
          // 清除选定对象的所有光标对象
          window.getSelection().removeAllRanges()
          // 插入新的光标对象
          window.getSelection().addRange(range)
   
          // 保存新光标
          this.recordPosition()
        })
      }
    }
  }
  </script>
   
  <style lang="scss">
  #formulaPage {
    width: 100%;
    height: 100%;
   
    > .formulaView {
      margin-bottom: 20px;
      min-height: 130px;
      width: 100%;
      padding: 5px;
      border: 5px solid rgb(198, 226, 255);
      resize: both;
      overflow: auto;
      line-height: 25px;
      font-size: 20px;
      span {
        user-select: none;
        display: inline-block;
        /* // margin: 0 3px; */
        height: 20px;
        line-height: 20px;
        /* // letter-spacing: 2px; */
        border-radius: 3px;
        white-space: nowrap;
        &:first-child {
          margin-left: 0;
        }
      }
    }
    .footerComtent {
      margin-top: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .infomationContent {
      display: flex;
      &-leftFlexbox {
        flex: 1;
        display: flex;
        > .tab {
          flex: 1;
          > ul {
            margin: 0;
            padding: 0;
            display: flex;
            flex-wrap: wrap;
            /* // justify-content: space-between; */
            &:after {
              content: '';
              display: table;
              clear: both;
            }
            > li {
              /* // margin-right: 20px; */
              margin: 5px 10px;
              width: 65px;
              text-align: center;
              float: left;
              padding: 0 10px;
              height: 30px;
              line-height: 30px;
              border-radius: 5px;
              font-weight: bold;
              border: 1px solid #fff;
              list-style-type: none;
              cursor: pointer;
              -moz-user-select: none; /* 火狐 */
              -webkit-user-select: none; /* 谷歌、Safari */
              -ms-user-select: none; /* IE10+ */
              user-select: none;
              user-drag: none;
              box-shadow: 0px 0px 2px 2px rgba(55, 114, 203, 0.2), /*下面深蓝色立体阴影*/ 0px 0px 6px 1px #4379d0,
                /*内部暗色阴影*/ 0 -15px 2px 2px rgba(55, 114, 203, 0.1) inset;
              color: #333333;
            }
   
            > li:hover {
              color: #fff;
              /* // color: #409eff; */
              border-color: #c6e2ff;
              background-color: #ecf5ff;
            }
            > li:active {
              color: #3a8ee6;
              border-color: #3a8ee6;
              outline: none;
            }
            .numberClass {
              width: 40px;
            }
            .typeClass {
              width: 100px
            }
            .symbolClass {
            }
            .noclick {
              cursor: not-allowed !important;
              background: #bcc0c4 !important;
              color: #e4eaf1 !important;
              border: none !important;
            }
          }
        }
      }
      &-rightBtnbox {
        width: 50px;
        padding-top: 10px;
        box-sizing: border-box;
        .imgboxinfo {
          width: 40px;
          height: 40px;
          img {
            cursor: pointer;
          }
        }
      }
    }
  }
  </style>

在父组件中引用即可

实现方式二

 1、效果图

2、实现代码

<!-- 配置计算公式 -->
    <el-dialog title="计算公式配置" :visible.sync="dragOpen" append-to-body :close-on-click-modal="false" width="1050px">
      <el-form label-width="90px" size="medium">
        <el-row>
          <el-col :span="24">
            <el-form-item label="调度指标:">
              <div style="border: 1px solid #c2ddf8;padding: 5px;">

                <draggable class="dragArea list-group" :list="indexLists" :group="{ name: 'people', pull: 'clone', put: false }" animation="300">
                  <el-tag v-for="tag in indexLists" :key="tag.id" effect="dark" class="fomula-tag" style="margin-right: 5px;" type="success">
                    {{tag.dictLabel}}
                  </el-tag>
                </draggable>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="24"></el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="运算符号:">
              <div style="border: 1px solid #c2ddf8;padding: 5px;">
                <draggable class="dragArea list-group" :list="operatorOptions" :group="{ name: 'people', pull: 'clone', put: false }" animation="300">
                  <el-tag v-for="tag in operatorOptions" :key="tag.id" effect="dark" class="fomula-tag" @click="tagClick(tag)" style="margin-right: 5px;background-color: #7c9096;border: none;width: 40px;text-align: center">
                    {{tag.dictLabel}}
                  </el-tag>
                </draggable>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="24"></el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="算数符号:">
              <div style="border: 1px solid #c2ddf8;padding: 5px;">
                <draggable class="dragArea list-group" :list="nums" :group="{ name: 'people', pull: 'clone', put: false }" animation="300">
                  <el-tag v-for="tag in nums" :key="tag.id" effect="dark" class="fomula-tag" @click="tagClick(tag)" style="margin-right: 5px;background-color: #2bcdff;border: none;width: 40px;text-align: center">
                    {{tag.dictLabel}}
                  </el-tag>
                </draggable>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="24"></el-col>
        </el-row>

        <el-row>
          <el-col :span="24">
            <el-form-item label="结果集:">
              <div style="border: 5px solid #c2ddf8;padding: 5px;position: relative;">
                <draggable class="list-group" :list="resultR" group="people" animation="300" style="height:100px;" @change="log">
                  <el-tag v-for="tag in resultR" :key="tag.id" effect="dark" @click="tagClick(tag)" closable @close="handleClose(tag)" style="margin-right: 5px;">
                    {{tag.dictLabel}}
                  </el-tag>
                </draggable>

                <el-popover placement="left" title="公式:" trigger="hover" :content="previewFormula">
                  <i class="el-icon-view show-fomula" slot="reference"></i>
                </el-popover>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <div class="explain">
              {{explain}}
            </div>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitDrag" v-if="this.confDisabled">保 存</el-button>
        <el-button @click="cancelDrag">取 消</el-button>
      </div>
    </el-dialog>

js方法

import draggable from 'vuedraggable'

​​​​​​​

watch: {
      'resultR': {
        handler: function () {
          this.refreshFormula();
        }
      },
    },
    methods: {
      log() {
        this.refreshFormula();
      },
      refreshFormula() {
        this.previewFormula = "";
        if (this.resultR !== undefined && this.resultR !== null && this.resultR !== []) {
          for (let i = 0; i < this.resultR.length; i++) {
            this.previewFormula += this.resultR[i].dictLabel;
          }
        }
        console.log("this.previewFormula")
        console.log(this.previewFormula)
      },
handleDrag(item) {
        indexList({ "factory": item.factory }).then(resp => {
          this.indexLists = resp.data;
          this.resultFormula = this.form.indicatorFormula
          if (typeof this.resultFormula !== 'undefined' && this.resultFormula.length > 0) {
            const strArr = this.resultFormula.split(',')
            this.resultR = [];
            for (let i = 0; i < strArr.length; i++) {
              let indexBoolean = false
              for (let j = 0; j < this.indexLists.length; j++) {
                if (this.indexLists[j].dictValue === strArr[i]) {
                  this.resultR.push(this.indexLists[j]);
                  indexBoolean = true
                }
              }
              if (!indexBoolean) {
                let opBoolean = false
                for (let z = 0; z < this.operatorOptions.length; z++) {
                  if (this.operatorOptions[z].dictValue === strArr[i]) {
                    this.resultR.push(this.operatorOptions[z]);
                    opBoolean = true
                  }
                }
                if (!opBoolean) {
                  for (let c = 0; c < this.nums.length; c++) {
                    if (this.nums[c].dictValue === strArr[i]) {
                      this.resultR.push(this.nums[c]);
                    }
                  }
                }
              }

            }
          }
          this.dragOpen = true;
        })
      },
      submitDrag() {
        console.log(this.resultR)
        this.resultFormula = ''
        for (let i = 0; i < this.resultR.length; i++) {
          this.resultFormula = this.resultFormula + this.resultR[i].dictValue + ","
        }
        this.$set(this.form, 'indicatorFormula', this.resultFormula.substring(0, this.resultFormula.length - 1));
        this.dragOpen = false;
        this.resultR = [];
        this.previewFormula = '';
      },
      cancelDrag() {
        this.dragOpen = false;
        this.previewFormula = '';
      },
      tagClick(item) {

      },
      handleClose(item) {
        this.resultR.splice(this.resultR.findIndex(i => i.dictValue === item.dictValue), 1);
      },
}

css代码

<style>
  .mpc-model-dialogue-box .el-dialog {
    width: 29%;
    height: auto;
  }

  .clearfix .el-checkbox__inner {
    margin-bottom: 8px;
  }

  .clearfix .el-checkbox__label {
    width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 16px;
    font-weight: bold;
    color: #409EFF;
  }

  .cardClass .el-card__header {
    padding: 10px 15px 0px;
  }

  .show-fomula {
    position: absolute;
    bottom: 10px;
    right: 10px;
    font-size: 20px;
    color: #237aeb;
  }

  .show-fomula:hover {
    opacity: 0.5;
    transition: 1s;
    transform: scale(1.3);
  }
  

  .fomula-tag:hover {
    opacity: 0.5;
    transform: scale(1.1);
    background-color: #2d52f7 !important;
  }
  

  .edit-fomula:hover {
    opacity: 0.5;
    transition: 1s;
    transform: scale(1.3);
    color: #43bb0b;
  }

  .explain {
    font-weight: bold;
    color: red;
    font-size: 12px;
    float: right;
  }
</style>

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

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

相关文章

pyqt5实现振动波形数据标注工具

pyqt5实现振动波形数据标注工具 1、效果图 2、实现功能 1、数据库连接 2、数据筛选 3、波形图展示、频谱图展示 4、特征展示&#xff1a;时域、频域 5、数据标注与添加 6、模型训练与分类识别3、部分核心代码 3.1、连接数据库 # -*- coding: utf-8 -*-""" c…

技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)

1. 引言 开源代码实现见&#xff1a; https://github.com/hashcloak/fhe_risc0_zkvm&#xff08;Rust&#xff09;https://github.com/weikengchen/vfhe-profiled&#xff08;Rust&#xff09;https://github.com/l2iterative/vfhe0&#xff08;Rust&#xff09; L2IV Resea…

后端开发——统一处理异常Spring MVC机制

一、Spring MVC的统一处理异常机制 在Spring MVC中&#xff0c;存在统一处理异常的机制&#xff0c; 具体表现为&#xff1a;无论是哪个处理请求的过程中出现异常&#xff0c;每种类型的异常只需要编写一段处理异常的代码即可&#xff01; 统一处理异常的核心是定义处理异常的…

【INTEL(ALTERA)】Agilex7 FPGA Development Kit DK-DEV-AGI027R1BES编程/烧录/烧写/下载步骤

DK-DEV-AGI027R1BES 的编程步骤&#xff1a; 将外部 USB Blaster II 连接到 J10- 外部 JTAG 接头。将交换机 SW5.3 设置为 ON&#xff08;首次&#xff09;。打开 英特尔 Quartus Prime Pro Edition 软件编程工具。单击 硬件设置 &#xff0c;然后选择 USB Blaster II。将硬件…

LeetCode - 460 LFU缓存(Java JS Python)

题目来源 460. LFU 缓存 - 力扣&#xff08;LeetCode&#xff09; 题目描述 请你为 最不经常使用&#xff08;LFU&#xff09;缓存算法设计并实现数据结构。 实现 LFUCache 类&#xff1a; LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象int get(int key)…

RocketMQ系统性学习-SpringCloud Alibaba集成RocketMQ以及消息追踪、延时消息实战

文章目录 消息追踪延时消息实战 消息追踪 设置消息追踪需要修改 broker 启动的配置文件&#xff0c;添加一行配置&#xff1a;traceTopicEnabletrue 即可&#xff0c;操作如下&#xff1a; # 进入到 rocketmq 的安装目录中 # 先复制一份配置文件 cp broker.conf custom.conf …

高并发音频转口型服务器开发

课程名称&#xff1a;高并发口型服务器开发 高并发口型服务器 哈喽&#xff0c;大家好&#xff0c;我叫人宅&#xff0c;很高兴和大家一起分享本套课程&#xff0c;高并发口型服务器开发。 虚拟人的口型一直是我们避免不了问题&#xff0c;即使我们不做虚拟人实时口型&#x…

WorkPlus搭建高效即时通讯,打造高效协作新标杆

在现代企业中&#xff0c;即时通讯已成为团队沟通和协作的重要组成部分。作为一款创新的即时通讯工具&#xff0c;WorkPlus致力于提供高效、便捷的沟通和协作体验&#xff0c;打造全新的企业沟通标杆。 WorkPlus的出色之处在于其高效的即时通讯能力。无论是团队内部交流还是跨团…

H266/VVC标准的编码结构介绍

概述 CVS&#xff1a; H266的编码码流包含一个或多个编码视频序列&#xff08;Coded Video Swquence&#xff0c;CVS&#xff09;&#xff0c;每个CVS以帧内随机接入点&#xff08;Intra Random Access Point&#xff0c; IRAP&#xff09;或逐渐解码刷新&#xff08;Gradual …

MySQL 教程 2.2

MySQL WHERE 子句 我们知道从 MySQL 表中使用 SELECT 语句来读取数据。 如需有条件地从表中选取数据&#xff0c;可将 WHERE 子句添加到 SELECT 语句中。 WHERE 子句用于在 MySQL 中过滤查询结果&#xff0c;只返回满足特定条件的行。 语法 以下是 SQL SELECT 语句使用 WH…

项目实战:自动驾驶之方向盘操纵

项目介绍 根据汽车前方摄像头捕捉的画面,控制汽车方向盘转动的方向和角度,这是自动驾驶要解决的核心问题。这个项目主要是通过使用深度神经网络解决一个回归问题。不同于分类、识别场景,回归问题中神经网络输出的是一个连续的值。 通过这个项目的学习,可以将神经网络用于通…

Python开源项目周排行 2023年第40周

Python 趋势周报&#xff0c;按周浏览往期 GitHub,Gitee 等最热门的Python开源项目&#xff0c;入选的项目主要参考GitHub Trending,部分参考了Gitee和其他。排名不分先后&#xff0c;都是当周相对热门的项目。 入选公式&#xff1d;70%GitHub Trending20%Gitee10%其他 关注微…

CSS 的背景属性(开发中常用)

目录 1 内容预览 背景颜色 背景图片 背景平铺 背景图片位置(常用) 背景图像固定 背景复合写法 背景色半透明 实现案例 1 内容预览 背景属性可以设置背景颜色、背景图片、背景平铺、背景图片位置、背景图像固定等。 注意&#xff1a; 把表格中的五个属背下来&#xff0c…

搞懂这6 个持续集成工具,领先80%测试人!

开发人员喜欢把写的代码当成自己的孩子&#xff0c;他们会被当成艺术品一样呵护。作为家长&#xff0c;总是会认为自己的孩子是最好的&#xff0c;也会尽全力给自己的孩子最好的&#xff0c;就算有时候会超出自己的能力范围。 最终&#xff0c;孩子会走出去&#xff0c;和其他…

京东看数据-京东运营数据分析-10月宠物市场销售数据分析(宠物店铺数据查询)

近年来&#xff0c;宠物成为越来越多家庭的成员&#xff0c;宠物数量不断增长&#xff0c;“宠物经济”异军突起&#xff0c;成为消费市场中特殊的存在。“撸猫”“吸狗”正迅速成为人们交际的热门谈资&#xff0c;宠物经济也迈入快速发展阶段。 根据鲸参谋电商数据分析平台的相…

fckeditor编辑器改造示例:增加PRE,CODE控件

查看专栏目录 Network 灰鸽宝典专栏主要关注服务器的配置&#xff0c;前后端开发环境的配置&#xff0c;编辑器的配置&#xff0c;网络服务的配置&#xff0c;网络命令的应用与配置&#xff0c;windows常见问题的解决等。 文章目录 修改方法&#xff1a;1&#xff09;修改fckco…

JS基本语法

JS基本语法 变量数据类型原始数据类型 函数定义第一种方式第二种方式 JS 对象ArrayStringJavaScript 自定义对象JSONDOMBOM JS 事件事件监听事件绑定常见事件 变量 数据类型 原始数据类型 函数定义 第一种方式 第二种方式 JS 对象 Array String JavaScript 自定义对象 JSON …

VR汽车技术服务虚拟仿真实训平台更好地辅助职业上岗培训

VR汽车虚拟仿真教学软件是一种基于虚拟现实技术的教学辅助工具。它能够模拟真实的汽车环境和操作场景&#xff0c;让学生能够通过虚拟仿真来学习和实践汽车相关知识和技能。 与传统的教学方式相比&#xff0c;VR汽车虚拟仿真教学软件具有更高的视觉沉浸感和互动性&#xff0c;能…

19.Tomcat搭建

Tomcat 简介 Tomcat的安装和启动 前置条件 • JDK 已安装(JAVA_HOME环境变量已被成功配置) Windows 下安装 访问 http://tomcat.apache.org ⇒ 左侧边栏 “Download” 2. 解压缩下载的文件到 “D:\tomcat”, tomcat的内容最终被解压到 “D:\tomcat\apache-tomcat-9.0.84” 3.…

Stable LM Zephyr 3B:手机上的强大LLM助手

概览 最近&#xff0c;Stability.ai宣布开源了Stable LM Zephyr 3B&#xff0c;这是一个30亿参数的大语言模型&#xff08;LLM&#xff09;&#xff0c;专为手机、笔记本等移动设备设计。其突出的特点是参数较小、性能强大且算力消耗低&#xff0c;能够自动生成文本、总结摘要…