当前位置: 首页 > news >正文

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;
}
http://www.dtcms.com/a/108663.html

相关文章:

  • 计算机视觉算法实战——基于YOLOv8的行人流量统计系统
  • 缺页异常导致的iowait打印出相关文件的绝对路径
  • Linux红帽:RHCSA认证知识讲解(十)使用 tar创建归档和压缩文件
  • RAG库搭建:从零开始,开启智能问答新世界
  • OpenCV 图形API(15)计算两个矩阵(通常代表二维向量的X和Y分量)每个对应元素之间的相位角(即角度)函数phase()
  • Ubuntu换Windows磁盘格式化指南
  • 二,<FastApi>FastApi的两个核心组件
  • JavaScript基础-window.sessionStorage
  • 通信算法之255:无人机频谱探测设备技术详解
  • 使用Kafka和kafkajs构建示例项目
  • 前端面试题(三):axios有哪些常用的方法
  • Linux上位机开发实践(从用板子到自己做板子)
  • 针对 SQL 查询中 IN 子句性能优化 以及 等值 JOIN 和不等值 JOIN 对比 的详细解决方案、代码示例及表格总结
  • Webpack vs Vite:现代前端构建工具的巅峰对决与选型指南
  • Linux学习七——进程回收
  • 一文详解QT环境搭建:Windows平台Qt安装配置指南
  • react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react18
  • 电脑异常关机导致oracle监听器启动后自动停止
  • 蓝桥杯 web 请到下一步
  • Spread使用 配合report使用前篇
  • python爬虫基础讲解
  • 【调用通义千问实现手写文字识别】
  • 04-08手写持久层框架——核心配置和映射配置文件解析
  • 从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.2.1视觉-语言模型(VLM)架构设计(CLIP与Flamingo模式)
  • HarmonyOS 基础组件和基础布局的介绍
  • Nyquist插件基础:LISP语法-条件语句
  • 数据量管理系统
  • 光学关键尺寸量测设备市场报告:2024年全球市场销售额达到了14.75亿美元
  • 鸿蒙NEXT开发土司工具类(ArkTs)
  • 前端中rem,vh,vw