vue使用Element的Tree树形控件实现拖动改变节点顺序方式

 更新时间:2023年12月06日 11:01:30   作者:hhtSeeTheWorld  
这篇文章主要介绍了vue使用Element的Tree树形控件实现拖动改变节点顺序方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

项目完成后,产品又提新需求,

通过拖动能够改变下面的组织顺序,又给我增加了好大的工作量!

先吐槽产品一波,怎么早先不想好呢!

首先要想实现拖动改变顺序,那我从后端查询得来的数据

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.draggabl.是否开.拖拽功能

2.allow-dro.拖拽时判定目标节点能否被放置。

3.node-dro.拖拽成功触发的事.  主要是我们 把数据发.后端

4.dat.我们要展示的数. 从后端获取. treeList

5.node-ke.每个树节点用来作为唯一标识的属性,整棵树应该是唯一的

6.current-node-ke.当前选中的节点

7.default-expanded-key.默认展开的节点.key 的数..  就是我们 想展开节点.id 数组

8.expand-on-click-nod. 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。

9.node-clic.节点被点击时的回.. 节点被点击.我们想做什么. 一般是查询

10.prop...主要用.指定 我们想展示节点.的那两个属. 属性.必须和 从后端得到数据.属性名 相对应

11.re..ref被用来给元素或子组. 注. 引用信息.引用信息将会注册在父组件的 $refs对象上。

12.filter-node-metho. 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏

13.highlight-curren.  是否高亮当前选中节点,默认值是 false。

14.el-toolti. 文字提. 用法 <el-tooltip> 要展示的内.</el-tooltip.  给这个 内容 做一些提示

. 当前我们前端要达到的效果.如果文字过. 很后面以省略号结.  但是有必须 让用.看.该条数据的全部内.所以.文字提示.方法去达到目的

. 当前这个文字提. 已经添..v-i.判断字数大于1.才会生效

........... v-els.  就显示原本的字数 

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

  • 属性 draggable 是否开启 拖拽功能
  • 属性 allow-drop 拖拽时判定目标节点能否被放置。
  • 事件 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);
        },

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

最新评论