项目完成后,产品又提新需求,
通过拖动能够改变下面的组织顺序,又给我增加了好大的工作量!
先吐槽产品一波,怎么早先不想好呢!
在这里插入图片描述
首先要想实现拖动改变顺序,那我从后端查询得来的数据

treeList

首先就必须有顺序,
后端为了实现节点有顺序—在实体类中又增加了一个字段
原先类实体

public class OrgNode {
    private String id;
    private String name;
    private String parentId;
}

增加了一个brotherId
当前类实体

public class OrgNode {
    private String id;
    private String name;
    private String parentId;
    private String brotherId;
}

后端

1.新增节点

每当我新增一个节点时,就把他的brotherId设为 “-1”,
如果新增节点所在的层级之前没有节点,那不需要处理;
如果新增节点所在的层级之前有节点,那么把之前brotherId为-1的节点的brotherId改为新增节点的id

2.删除节点

当删除节点时,为保证顺序,需要把 被删节点 后一个节点的brotherId 改为 被删节点的 brotherId,
这样这一层级的节点顺序才不会出错

以上写了一点后端的做法,下面来详细讲解前端实现
在这里插入图片描述
属性结构的代码

   <el-tree :draggable="true" @node-drop="testTrop" :allow-drop="dropPosition" :data="organization" node-key="id" :current-node-key="currentNode" :default-expanded-keys="keys" :expand-on-click-node="false"
        @node-click="nodeClick" :props="defaultProps" ref='treeOrg' :filter-node-method='filterNode' highlight-current>
        <span class="custom-tree-node" slot-scope="{ node, data }">
          <el-tooltip v-if="node.label.length>10" :content='node.label' placement="top-start" effect="dark"
            popper-class="atooltip">
            <span>{{node.label | showTreeName}}</span>
          </el-tooltip>
          <span v-else>{{ node.label }}</span>
          <span v-if="node.data.id==selectId">
            <el-button type="text" icon="el-icon-edit" size="mini" @click.stop=" () => updateOrganization(data)"></el-button>
            <el-button type="text" icon="el-icon-delete" size="mini" @click.stop="() => remove(node, data)"></el-button>
          </span>
        </span>
      </el-tree>

该组织树的使用

1.  属性  draggable  是否开启  拖拽功能
2.  属性  allow-drop  拖拽时判定目标节点能否被放置。
3.  事件  node-drop  拖拽成功触发的事件    主要是我们 把数据发给  后端
4.  data  我们要展示的数据   从后端获取的   treeList
5.  node-key  每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
6.  current-node-key  当前选中的节点
7.  default-expanded-keys  默认展开的节点的  key 的数组       就是我们 想展开节点的  id 数组
8. expand-on-click-node   是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。
9.  node-click  节点被点击时的回调      节点被点击时  我们想做什么事   一般是查询
10.  props        主要用来  指定 我们想展示节点的  的那两个属性   属性名  必须和 从后端得到数据的  属性名 相对应
11.  ref     ref被用来给元素或子组件   注册   引用信息。  引用信息将会注册在父组件的 $refs对象上。
12. filter-node-method   对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
13. highlight-current    是否高亮当前选中节点,默认值是 false。
14. el-tooltip   文字提示   用法 <el-tooltip> 要展示的内容  </el-tooltip>    给这个 内容 做一些提示
    当前我们前端要达到的效果是  如果文字过长   很后面以省略号结束    但是有必须 让用户  看到  该条数据的全部内容  所以用  文字提示的  方法去达到目的
    当前这个文字提示   已经添加     v-if  判断字数大于10  才会生效
                                  v-else    就显示原本的字数

这里主要讲解拖拽的两个属性,一个事件

  1. 属性 draggable 是否开启 拖拽功能
  2. 属性 allow-drop 拖拽时判定目标节点能否被放置。
  3. 事件 node-drop 拖拽成功触发的事件 主要是我们 把数据发给 后端
    在这里插入图片描述
    在这里插入图片描述
    第一个draggable没什么好讲的
    第三个node-drop用法也简单
    在这里插入图片描述
    本人主要是
    在这里插入图片描述
    我被该属性卡住了

因为我的是有一个限制,同级中不能有同名组织,
所以需要判定 被拖组织 能否置于 目标组织 前面,后面,或者内部

dropPosition(draggingNode, dropNode, type) {
        console.log(draggingNode);
        console.log(dropNode);
        console.log(type);
        //这三个参数  是我们在页面拖动时   我们停止拖动时   会自动生成的参数三个参数
        // 转移节点draggingNode  目标节点dropNode   置于目标节点的位置  type='prev'、'inner' 和 'next'  三个中其中一个
        if (type === "inner") {
          checkOrganizationName(draggingNode.data.id, draggingNode.data.name, dropNode.data.id).then(data => {
            if (data.data.data === true) {
              //说明目标节点内部存在  与转移节点  相同名称的  节点,不能转入
              //那我们不设返回值  就不会触发移动事件
            } else {
              return "inner";
            }
          });
        } else if (type === "prev" || type === "next") {
          //判断转移节点   能否放置于  目标节点的  前面或者后面
          checkOrganizationName(draggingNode.data.id, draggingNode.data.name, dropNode.data.parentId).then(data => {
            if (data.data.data === true) {
              //说明 前后不能放
              //那我们也不设返回值  就不会触发移动事件
            } else {
              return type;
            }
          });

        }
      },

在这里插入图片描述
在这里插入图片描述
所以不能通过向后端发请求的方式,判断能否放于 目标位置

应该通过比较前端已经有的数据,判断能否放于目标位置

在这里插入图片描述

 processDataTree(data) {
        for (let index in data) {
          let obj = data[index];
          this.organizationTemp.push({id: obj.id, name: obj.name, parentId: obj.parentId});
          if (obj.children !== null && obj.children.length > 0) {
            this.processDataTree(obj.children);
          }
        }
      },
      getOrganizationTemp() {
        getOrganization().then(data => {
          this.organizationAfterMove = data.data.data;
          this.organizationTemp = [];
          this.processDataTree(this.organizationAfterMove);
        });
      },
      dropPosition(draggingNode, dropNode, type) {
        //这三个参数  是我们在页面拖动时   我们停止拖动时   会自动生成的参数三个参数
        // 转移节点draggingNode  目标节点dropNode   置于目标节点的位置  type='prev'、'inner' 和 'next'  三个中其中一个
        if (type === "inner") {
          if (dropNode.data.children===null){
            //目标节点没有子节点  可以直接放入
            return "inner"
          }else {
            let childArray=dropNode.data.children;
            for (let i = 0; i < childArray.length; i++) {
              if (childArray[i].name===draggingNode.data.name){
                return
              }
            }
            return "inner"
          }
        } else if (type === "prev" || type === "next") {
          let existObj;
          for (let i = 0; i <this.organizationTemp.length; i++) {
            let obj = this.organizationTemp[i];
            if(obj.parentId === dropNode.data.parentId && obj.name === draggingNode.data.name && obj.id!==draggingNode.data.id){
               existObj=obj;
            }
          }
          if (existObj) {

          } else {
            return type;
          }
        }
      },

        testTrop(before,after,inner,event){
            changeParentOrg(before.data.id,after.data.id,inner,this.$getCookie().getUserName());
            setTimeout(()=>{this.getOrganizationTemp()},500);
        },

在这里插入图片描述
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐