vue2拖拉拽做个模拟公式工具

1. 成图

在这里插入图片描述

2. 介绍

就是简单拖拉拽来做个规则运算器,具体运算规则、校验规则自己加。

3. 代码

HTML代码

<template>

    <div class="red-cont">
      <div class="red-top">
        <div
          class="red-top-left"
        >
          <div class="red-showarea">
            <div class="red-showarea-title">公式展示</div>
            <div class="red-showarea-list">
              <span
                v-for="(item, index) in valueList"
                :key="index"
              >{{ item.label }}</span>
            </div>
          </div>
          <div class="red-ctrlarea  user-no-select">
            <div class="red-ctrlarea-title">公式编辑</div>
            <div
              class="red-ctrlarea-list"
              @drop="handleDrop"
              @dragleave="handleDragLeave($event)"
              @dragover.stop.prevent="handleDragOver($event)"
            >
              <div v-if="valueList.length === 0" class="red-ctrlarea-hint">
                请拖曳字段、数字或操作符到编辑区域
              </div>
              <div
                v-for="(item, index) in valueList"
                :key="item.id"
                :class="[
                  'red-ctrl-item',
                  index === draggingOverIndex - 1 ? 'red-ctrl-inject-before' : '',
                  index === draggingOverIndex ? 'red-ctrl-inject-after' : ''
                ]"
                @drop.stop.prevent="handleDrop"
                @dragover.stop.prevent="handleDragOver($event, index)"
              >
                <div
                  class="red-ctrl-item-cont"
                  draggable="true"
                  @dragstart="handleDragStart($event, item, item.type)"
                >
                  <div :alt="item.label">{{ item.label }}</div>
                  <i
                    class="el-icon-circle-close red-ctrl-item-close"
                    @click="removeValueItem(item, index)"
                  />
                </div>

              </div>
            </div>
          </div>
        </div>
        <div class="red-top-right user-no-select">
          <div class="red-paramtype">
            <el-select v-model="paramType">
              <el-option
                v-for="item in paramTypeOptions"
                :key="item.value"
                :label="item.label"
                :disabled="item.disabled"
                :value="item.value"
              />
            </el-select>
          </div>
          <div class="red-paramoptions">
            <div
              v-for="(item, index) in paramOptions"
              :key="index"
              class="red-paramoptions-item"
              draggable="true"
              @dragstart="handleDragStart($event, item, paramType)"
            >
              {{ item.label }}
            </div>
          </div>
        </div>
      </div>
      <div class="red-bottom user-no-select">
        <div class="red-bottom-left">
          <div
            v-for="(item, index) in sourceList"
            :key="index"
            class="red-source-item"
            draggable="true"
            @dragstart="handleDragStart($event, item, 'ctrl')"
          >
            {{ item.label }}
          </div>
        </div>
        <div
          class="red-clear"
          @click="clearValueList"
        ><br></div>
      </div>
    </div>
</template>

VUE2的代码

export default {
  components: {},
  props: {},
  data() {
    return {
      paramType: 'field',
      paramTypeOptions: [
        { value: 'field', label: '字段' },
        { value: 'attribute', label: '机组属性', disabled: true }
      ],

      paramOptions: [
        { value: Math.random(), label: '字段1' },
        { value: Math.random(), label: '字段2' },
        { value: Math.random(), label: '字段3' },
        { value: Math.random(), label: '字段4' },
        { value: Math.random(), label: '字段5' }
      ],

      valueList: [],

      sourceList: [
        { label: '1', value: '1' },
        { label: '2', value: '2' },
        { label: '3', value: '3' },
        { label: '4', value: '4' },
        { label: '5', value: '5' },
        { label: '6', value: '6' },
        { label: '7', value: '7' },
        { label: '8', value: '8' },
        { label: '9', value: '9' },
        { label: '0', value: '0' },
        { label: '00', value: '00' },
        { label: '(', value: '(' },
        { label: ')', value: ')' },
        { label: '.', value: '.' },
        { label: '+', value: '+' },
        { label: '-', value: '-' },
        { label: '*', value: '*' },
        { label: '/', value: '/' },
        { label: '>', value: '>' },
        { label: '<', value: '<' },
        { label: '==', value: '==' },
        { label: '>=', value: '>=' },
        { label: '<=', value: '<=' },
        { label: '!', value: '!' },
        { label: '||', value: '||' },
        { label: '&&', value: '&&' }
      ],

      draggingIndex: null,
      draggingOverIndex: null
    };
  },
  created() {},
  methods: {
    clearValueList() {
      this.valueList.splice(0, this.valueList.length);
    },

    handleDragLeave(e) {
      console.log('tree drag leave: ', e);
      this.draggingOverIndex = null;
    },

    handleDrop(e) {
      const data = JSON.parse(e.dataTransfer.getData('text/plain'));

      const { valueList, draggingOverIndex } = this;
      const item = Object.assign({}, data, {
        id: Math.random().toString(36).substr(2, 9)
      });

      if (typeof draggingOverIndex === 'number') {
        valueList.splice(draggingOverIndex, 0, item);

        const dataIndex = valueList.findIndex(item => item.id === data.id);

        if (dataIndex !== -1) {
          valueList.splice(dataIndex, 1);
        } else {
          //
        }
      } else {
        const dataIndex = valueList.findIndex(item => item.id === data.id);

        if (dataIndex !== -1) {
          valueList.splice(dataIndex, 1);
        } else {
          //
        }

        valueList.push(item);
      }

      this.draggingOverIndex = null;
    },

    handleDragOver(e, targetIndex) {
      console.log('handleDragOver', e, targetIndex);

      this.draggingOverIndex = targetIndex;
    },

    handleDragStart(e, item, type) {
      e.dataTransfer.setData('text/plain', JSON.stringify(Object.assign({
        type: type
      }, item)));
    },

    removeValueItem(item, index) {
      this.valueList.splice(index, 1);
    }
  }
};

less/scss代码

.red-cont{
    display: flex;
    height: 100%;
    overflow: hidden;
    flex-direction: column;
}
.red-top{
    flex: 1;
    overflow: hidden;
    display: flex;
    align-items: stretch;
    justify-content: space-between;
}
.red-top-left{
    flex: 1;
    overflow: hidden;
}
.red-showarea{
    display: flex;
    flex-direction: column;
    height: 35%;
}
.red-showarea-title{
    flex-shrink: 0;
}
.red-showarea-list{
    flex: 1;
    overflow: auto;
    padding: 10px;
}
.red-ctrlarea{
    display: flex;
    flex-direction: column;
    height: 65%;
}
.red-ctrlarea-title{
    flex-shrink: 0;
}
.red-ctrlarea-hint{
    padding: 10px;
    color: #ccc;
}
.red-ctrlarea-list{
    flex: 1;
    overflow-x: hidden;
    overflow-y: auto;
    border: 1px dashed #ccc;

    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
}
.red-ctrl-item{
    padding-left: 10px;
    padding-top: 10px;
    max-width: 200px;
}
.red-ctrl-inject-before{
    &>.red-ctrl-item-cont{
        border-right: 1px dashed #ccc;
    }
}
.red-ctrl-inject-after{
    &>.red-ctrl-item-cont{
        border-left: 1px dashed #ccc;
    }
}
.red-ctrl-item-cont{
    padding: 5px;
    position: relative;
    cursor: grab;
    border: 1px solid transparent;

    &>div{
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}
.red-ctrl-item-close{
    position: absolute;
    top: -5px;
    right: -5px;
    cursor: pointer;
}
.red-paramtype{
    flex-shrink: 0;
    padding: 10px;
    .el-select{
        width: 100%;
    }
}
.red-paramoptions{
    flex: 1;
    padding: 10px;
    overflow: auto;
}
.red-paramoptions-item{
    padding: 5px;
    cursor: grab;
    &:hover{
        background-color: #ccc;
    }
}
.red-bottom{
    flex-shrink: 0;
    height: 200px;
    display: flex;
    align-items: center;

}
.red-bottom-left{
    flex: 1;
    display: flex;
    flex-wrap: wrap;
    padding: 1px;
}
.red-clear{
    padding: 10px;
    border: 1px solid #fff;
    cursor: grab;
}
.red-source-item{
    width: 50px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    margin: 5px;
    background-color: #ccc;
    cursor: grab;
}
求关注
在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值