• 组件之间的拖拽


    项目中涉及到三种类型的拖拽:

    1.el-tree拖拽字段至div,表格;

    2.多个div之间的拖拽;

    3.表格之间列的拖拽;

    实现代码:

    1.el-tree拖拽字段至div,表格;

     1.el-tree设置字段可拖拽至外部:

    <el-tree
      ref="tree"
      @node-drag-start="handleDragStart"
      @node-drag-enter="handleDragEnter"
      @node-drag-leave="handleDragLeave"
      @node-drag-over="handleDragOver"
      @node-drag-end="handleDragEnd"
      @node-drop="handleDrop"
      draggable
      :allow-drop="allowDrop"
      :allow-drag="allowDrag"
    >
    
    handleDragStart(node, ev) {
      let dt = ev.dataTransfer;
      ev.dataTransfer.effectAllowed = "copy";
      dt.setData("text/plain", JSON.stringify(node.data));
    },
    handleDragEnter(draggingNode, dropNode, ev) {},
    handleDragLeave(draggingNode, dropNode, ev) {},
    handleDragOver(draggingNode, dropNode, ev) {},
    handleDragEnd(draggingNode, dropNode, dropType, ev) {},
    handleDrop(draggingNode, dropNode, dropType, ev) {},
    allowDrop(draggingNode, dropNode, type) {
      return false;
    },
    allowDrag(draggingNode) {
      return true;
    },
    

    2.div及表格设置可接收el-tree拖拽过来的字段信息:

    @drop="(e) => handleTargetDrop(e, index)"
    @dragover.prevent
    
    // 字段列表拖拽字段至报表列
    handleTargetDrop(e, index) {
      let data = e.dataTransfer;
      if (!this.isJsonString(data.getData("text/plain"))) return;
      let content = JSON.parse(data.getData("text/plain"));
      let newList = JSON.parse(JSON.stringify(this.listCheckedFields));
      newList.splice(index + 1, 0, content);
      this.dragRowColumnReportColumns(newList);
      e.preventDefault();
      // 通常不需要阻止冒泡,但是当出现容器嵌套时最好这么做
      // 它可以防止节点被添加到数组中两次
      e.stopPropagation();
    },
    
    // 判断是否可以转换为json数据
    isJsonString(str) {
      try {
        if (typeof JSON.parse(str) == "object") {
          return true;
        }
      } catch (e) {}
      return false;
    },

    若是用在表格中则drop方法需要添加到表头标签上,事件中可以获取到拖拽过来的字段信息,若是想要拖拽到固定位置,可以在循环的表头或div中传入index来动态插入。

    dragRowColumnReportColumns方法用来在获取到拖拽之后的数据集合时,通过请求接口来渲染页面数据。

    2.多个div之间的拖拽;

     1.组行、组列、报表列这三个div之间可以互相拖拽;可以将这三个div进行分组;

    <draggable
      v-model="form.choosedColumnFiledsData"
      @update="dragRowColumnReportColumns"
      @add="dragRowColumnReportColumns"
      v-bind="dragOptions"
    >
    </draggable>
    
    computed: {
      dragOptions() {
        return {
          animation: 300,
          group: "description",
          ghostClass: "ghost",
          chosenClass: "chosen",
        };
      },
    },
    
    // 组行、组列、报表列拖拽
    dragRowColumnReportColumns() {
      // 数组去重
      this.form.chooseReportColumnsData = this.unique(
        this.form.chooseReportColumnsData
      );
      let e = {
        chooseRowFiledsData: this.form.chooseRowFiledsData,
        choosedColumnFiledsData: this.form.choosedColumnFiledsData,
        chooseReportColumnsData: this.form.chooseReportColumnsData,
      };
      this.$bus.$emit("dragRowColumnReportColumnsBus", e);
    },

     通过在dragOptions中设置相同的group,可以实现对应div之间的互相拖拽,各自内部也可以拖拽,然后通过v-model绑定拖拽之后的数据,在update和add方法中将拖拽后的数据请求接口,渲染页面。

    3.表格之间列的拖拽;

     表格的列之间可以互相拖拽;

    1.给表格的父元素设置class,给el-table设置v-if:

    <div class="draggable">
      <el-table
        :data="tableData"
        border
        :fit="true"
        :cell-style="cellClass"
        v-if="showTable"
      >
    
      </el-table>
    </div>

    因为使用Sortable.create进行拖拽后,表格会直接修改为拖拽之后的,尽管表格绑定的列数据并未改变,所以需要使用v-if来控制表格的重新渲染。

    2.表格列进行拖拽时,获取到拖拽之后的数据,请求接口:

    // 表格列的拖拽
    columnDrop() {
      const wrapperTr = document.querySelector(
        ".draggable .el-table__header-wrapper tr"
      );
      if (!wrapperTr) return;
      this.sortable = Sortable.create(wrapperTr, {
        animation: 180,
        delay: 0,
        dragClass: "chosen",
        onEnd: (evt) => {
          let newList = JSON.parse(JSON.stringify(this.listCheckedFields));
          const oldItem = newList[evt.oldIndex];
          newList.splice(evt.oldIndex, 1);
          newList.splice(evt.newIndex, 0, oldItem);
          // 拖拽之后会改变表格列顺序,目前没办法控制,但数据并未改变,可以重新渲染表格来维持原数据
          this.showTable = false;
          this.$nextTick(() => {
            this.showTable = true;
          });
          this.dragRowColumnReportColumns(newList);
        },
      });
    },

    获取到拖拽之后的数据之后,请求接口,渲染页面。

     3.当表头数据改变后,拖拽方法需要重新调用,不然拖拽会不生效:

    watch: {
      listCheckedFields: {
        handler(newVal, oldVal) {
          this.$nextTick(() => {
            this.columnDrop();
          });
        },
        deep: true,
        immediate: true,
      },
    },
    

    注意:

    1.三种拖拽中,第一种拖拽,即从el-tree中将字段拖拽至外部区域这种,仅能获取到拖拽字段的信息,无法获取到拖拽后的数据集合,所以需要根据drop绑定的事件再结合拖拽到目标位置的下标来组合拖拽后的数据;

    2.后两种拖拽,即多个div之间的拖拽、el-table之间的拖拽,这两种均可以获取到拖拽之后的数据,这样就可以免去组装数据,直接将拖拽后的数据作为入参请求接口即可。

    3.参考:

    https://blog.csdn.net/qq_41694291/article/details/101384209

    https://www.jianshu.com/p/34f44f2eb668

    https://github.com/David-Desmaisons/draggable-example

    https://blog.csdn.net/weixin_41192489/article/details/114086578

    https://www.cnblogs.com/wisewrong/p/8820508.html

  • 相关阅读:
    vue 之 数据传递(子传父,父传子,非父子通信<事件总线>,父取子<ref,$refs>,插槽,provide和inject数据传递)
    vue 之 $ref 和 $refs
    node 之 身份认证(cookie,session,token<jwt>)
    vue 之 事件总线(订阅者模式,非父子间的数据传递)
    node 之 模块汇总
    node 之 web开发模式
    node 之 路由(待完善)
    node 之 浏览器跨域问题(待完善)
    Apache配置URL重定向
    自定义去除博客园底部的广告和链接推荐
  • 原文地址:https://www.cnblogs.com/5201314m/p/14649446.html
Copyright © 2020-2023  润新知