拖拽draggable

lishihuan大约 3 分钟

拖拽draggable

案例

image-20240327153549006
image-20240327153549006
end(event) {
        const mouseX = event.originalEvent.x;
        const mouseY = event.originalEvent.y;
        const plumbBox = document.querySelector('.plumbBox');
        const tableRect = plumbBox.getBoundingClientRect();

        if (
          mouseX >= tableRect.left &&
          mouseX <= tableRect.right &&
          mouseY >= tableRect.top &&
          mouseY <= tableRect.bottom &&
        ) {
          const cellElement = document.elementFromPoint(mouseX, mouseY); // 能知道,当前拖拽过来的元素所在父元素
          const tdElement = cellElement.closest('td'); // 拿到最近的td父元素(也可能是自身)
          if (cellElement && cellElement.tagName === 'TD' ) { // 验证是否是拖拽到指定的td单元格内
              //const rowId = cellElement.getAttribute('data-row-id');// 通过getAttribute 获取自定义属性
          	// 拖拽后执行
          }
        }
      },
<template>
  <div class="flowBox flow-content bk main-wrap">
    <div class="leftMenu">
      <div class="menu-title df_center">左侧菜单</div>
      <draggable @start="start" @end="end" :sort="false" class="node-wrap df_fdc_ac">
        <div v-for="(item, index) in leftMenuList" :key="item.id" @mousedown="(el) => downNode(el, item)"
             class="leftNode node" :class="item.type"> {{ item.name }}
        </div>
        <h4>操作提示</h4>
        <hr/>
        <p>左侧拖拽至右侧画布</p>
        <p>右键节点是删除节点,左键线条是删除线条</p>
        <el-button size="meduim" type="primary" @click="saveFlow">保存流程</el-button>
      </draggable>
    </div>
    <div class="plumbBox">

      <table class="bordered-table">
        <thead>
        <tr>
          <th :colspan="tableHeaders.length">防山火现场处置方案</th>
        </tr>
        <tr>
          <th v-for="header in tableHeaders" :key="header.ename">{{ header.name }}</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="(row, rowIndex) in tableData" :key="row.id">
          <td :id="'row_'+rowIndex+'_col_'+colIndex" v-for="(column, colIndex) in tableHeaders"
              :key="column.ename" :class="['row_'+rowIndex,'col_'+colIndex]"
              @drop="drop($event, row,column)" @dragover="allowDrop($event)">
            {{ row[column.ename] }}
          </td>
        </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
  import {leftMenuList} from "./js/data";
  import draggable from "vuedraggable";

  export default {
    name: 'demo1',
    components: {draggable},
    data() {
      return {
        leftMenuList: leftMenuList,
        dataList: [],
        tableHeaders: [
          { name: '角色1', ename: 'juese1' },
          { name: '角色2', ename: 'juese2' },
          { name: '角色3', ename: 'juese3' },
          { name: '角色4', ename: 'juese4' },
          { name: '角色5', ename: 'juese5' },
          { name: '角色6', ename: 'juese6' },
        ],
        tableData: [
          {id: 0, firstColumn: '火情报出', juese1:[],juese2:[],juese3:[],juese4:[],juese5:[],juese6:[],},
          {id: 1, firstColumn: '先期处理', juese1:[],juese2:[],juese3:[],juese4:[],juese5:[],juese6:[],},
          {id: 2, firstColumn: '启动相应', juese1:[],juese2:[],juese3:[],juese4:[],juese5:[],juese6:[],},
        ],
        selectedNode: null,
        currentRow: null, // 行
        currentCol: null,// 当前选中的列
      }
    },
    methods: {
      start() {
      },
      end(event) {
        const mouseX = event.originalEvent.x;
        const mouseY = event.originalEvent.y;
        const plumbBox = document.querySelector('.plumbBox');
        const tableRect = plumbBox.getBoundingClientRect();

        if (
          mouseX >= tableRect.left &&
          mouseX <= tableRect.right &&
          mouseY >= tableRect.top &&
          mouseY <= tableRect.bottom &&
          this.selectedNode
        ) {
          const cellElement = document.elementFromPoint(mouseX, mouseY);
          console.log(cellElement)
          if (cellElement && cellElement.tagName === 'TD') {
            const rowId = cellElement.getAttribute('data-row-id');
            // const selectedRow = this.tableData.find(row => row.id === Number(rowId));
            console.log(this.currentRow,this.currentCol)
            this.currentRow[this.currentCol.ename].push(this.selectedNode)
            console.log(this.tableData)
          }
        }

      },
      downNode(event, nodeItem) {
        this.selectedNode = nodeItem;
      },
      drop(event, rowItem,colItem) {
        event.preventDefault();
        this.currentRow = rowItem;
        this.currentCol = colItem;
      },
      allowDrop(event) {
        event.preventDefault();
      },
      saveFlow() {
        // 保存流程的逻辑
      }
    }
  }
</script>

<style lang="scss" scoped>
  .main-wrap {
    color: #fff !important;
  }

  .bordered-table {
    border-collapse: collapse;
    width: 100%;
  }

  .bordered-table th,
  .bordered-table td {
    border: 1px solid #fff;
    padding: 8px;
  }

  .col_0 {
    line-height: 1.5; /* 设置合适的值,使字体垂直居中 */
    writing-mode: vertical-rl; /* 第一列的文字垂直布局*/
    width: 50px;
  }


  .flowBox {
    display: flex;
    height: 100%;
    color: #fff;
  }

  .leftMenu {
    /*width: 300px;*/
    width: 200px;
    /* height: 100%; */
    border: 1px solid #fff;
    padding: 20px 10px;

    .menu-title {
      font-size: 18px;
      font-weight: 600;
    }

    .leftNode {
      /* width: 150px;*/
      margin-bottom: 30px;
    }


  }


  .plumbBox {
    flex: 1;
    /* height: 100%; */
    position: relative;

    /*background: url(./icon/grid-background.png);
    background-size: 50px 50px;*/
  }

  /* 节点 样式 目前总共分为 2类,一类是 时间节点,一类是 流转节点*/
  .node {
    width: 150px;
    height: 60px;
    display: flex;
    justify-content: center;
    align-items: center;
    border: dashed 1px #fff;
    cursor: move;

    &.timeNode {
      border-radius: 50%;
      border: 1px solid #fff;
    }

    &.flowNode {
      border: 1px solid #fff;
      border-radius: 4px;
    }

    &:hover {
      border: 2px dashed #1f77f3;
    }

    &.check {
      border: 2px solid #1f77f3;
      /* 最好加个阴影啥的*/
    }
  }

  //  连线的节点
  .pointNode {
    border-radius: 50%;
    width: 10px;
    height: 10px;
    position: absolute;
    bottom: -5px;
    left: 50%;
    transform: translateX(-50%);
    -o-border-image: initial;
    /* border-image: initial; */
    background: white;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    border: 3px solid royalblue;

    &:hover {
      background: royalblue;
      border: none;
      cursor: pointer;
    }
  }
</style>

案例

https://blog.csdn.net/weixin_56718509/article/details/133863083open in new window

https://huaweicloud.csdn.net/653f71c734bf9e25c799bcc1.htmlopen in new window

https://stackblitz.com/edit/vitejs-vite-rkwugn?file=README.mdopen in new window

类似app端拖拽排序 https://blog.csdn.net/sinat_28071063/article/details/102372442open in new window