封装了一个树形组件 实现添加自定义节点、上移、下移

效果展示

在这里插入图片描述

实例代码

<template>
  <div id="organizingStaff" class="flex-box">
    <div class="remark">
      <span>
        tips: <i class="el-icon-remove"></i>删除节点,
        <i class="el-icon-circle-plus"></i>添加节点,
        <i class="el-icon-top"></i>上移, <i class="el-icon-bottom"></i>下移,
        <i class="el-icon-user-solid"></i>用户
      </span>
    </div>
    <div style="width: 100%" class="flex-column">
      <el-tree
        ref="menutree"
        class="tree"
        :data="treeData"
        show-checkbox
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
      >
        <span class="custom-tree-node" slot-scope="{ node, data }">
          <span>{{ node.label }}</span>
          <span>
            <el-button type="text" size="mini" @click="remove(node, data)">
              <i class="el-icon-remove"></i>
            </el-button>
            <el-button
              v-if="data.type == 'BM'"
              type="text"
              size="mini"
              @click="editNode(data)"
            >
              <i class="el-icon-circle-plus"></i>
            </el-button>
            <el-button
              type="text"
              size="mini"
              @click="menuMoveF(node, data, 'up')"
            >
              <i class="el-icon-top"></i>
            </el-button>
            <el-button
              type="text"
              size="mini"
              @click="menuMoveF(node, data, 'down')"
            >
              <i class="el-icon-bottom"></i>
            </el-button>
            <el-button
              v-if="data.type == 'BM'"
              type="text"
              size="mini"
              @click="choseUser(data)"
            >
              <i class="el-icon-user-solid"></i>
            </el-button>
          </span>
        </span>
      </el-tree>
    </div>
    <el-dialog
      title="新建节点"
      :visible.sync="nodeDialog"
      width="50%"
      append-to-body
    >
      <el-form ref="form" label-width="80px" size="mini">
        <el-form-item label="节点名称:" label-width="100px">
          <el-input placeholder="请输入节点名称" v-model="nodeName"></el-input>
        </el-form-item>
        <el-form-item
          label-width="40px"
          style="float: right; margin-top: -10px"
        >
          <el-button
            type="primary"
            round
            icon="el-icon-circle-check"
            @click="append(nodeData)"
            >确定</el-button
          >
          <el-button
            type="primary"
            round
            icon="el-icon-delete"
            @click="nodeDialog = false"
            >取消</el-button
          >
        </el-form-item>
      </el-form>
    </el-dialog>
    <el-dialog
      title="选择用户"
      :visible.sync="userDialog"
      width="60%"
      append-to-body
    >
      <el-form
        ref="form"
        inline
        :model="userForm"
        label-width="80px"
        size="mini"
      >
        <el-form-item label="姓名:" label-width="100px">
          <el-input
            style="width: 150%"
            placeholder="请输入姓名"
            v-model="userForm.userName"
          ></el-input>
        </el-form-item>
        <el-form-item style="float: right">
          <el-button type="primary" round icon="el-icon-search">查询</el-button>
        </el-form-item>
      </el-form>
      <el-table
        ref="userTable"
        :data="userTable"
        border
        style="width: 100%"
        size="small"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column type="index" label="序号"></el-table-column>
        <el-table-column prop="userName" label="姓名"></el-table-column>
        <el-table-column prop="dept" label="部门"></el-table-column>
      </el-table>
      <el-form size="mini" style="float: right">
        <el-form-item label-width="40px">
          <el-button
            type="primary"
            round
            icon="el-icon-circle-check"
            @click="editUser(userNodeData)"
            >确定</el-button
          >
          <el-button
            type="primary"
            round
            icon="el-icon-delete"
            @click="userDialog = false"
            >取消</el-button
          >
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import CircularJSON from "circular-json";
let id = 1000;
export default {
  name: "organizingStaff",
  data() {
    return {
      userSelection: [],
      userTable: [
        {
          userName: "张三",
          dept: "综合管理部",
        },
        {
          userName: "李四",
          dept: "综合管理部",
        },
        {
          userName: "王五",
          dept: "综合管理部",
        },
      ],
      userForm: {},
      userDialog: false,
      nodeDialog: false,
      nodeName: "",
      nodeData: undefined,
      userNodeData: undefined,
      treeData: [
        {
          id: 1,
          label: "公司领导",
          type: "BM",
          children: [
            {
              id: 2,
              label: "二级 1-1",
              type: "BM",
              children: [
                {
                  id: 3,
                  label: "三级 1-1-1",
                  type: "RY",
                },
              ],
            },
          ],
        },
        {
          id: 4,
          label: "公司中层",
          type: "BM",
          children: [
            {
              id: 5,
              label: "二级 2-1",
              type: "RY",
            },
          ],
        },
      ],
    };
  },
  watch: {},
  created() {},
  methods: {
    //添加节点
    append(data) {
      if (
        this.nodeName == undefined ||
        this.nodeName == "" ||
        this.nodeName == null
      ) {
        this.$message.warning("请输入节点名称");
        return;
      }
      const newChild = {
        id: id++,
        label: this.nodeName,
        type: "BM",
        children: [],
      };
      if (!data.children) {
        this.$set(data, "children", []);
      }
      data.children.push(newChild);
      this.nodeDialog = false;
    },
    //移除节点
    remove(node, data) {
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex((d) => d.id === data.id);
      children.splice(index, 1);
    },
    editNode(data) {
      this.nodeName = "";
      this.nodeDialog = true;
      this.nodeData = data;
    },
    // 移动点击函数(node:当前节点,data:当前节点的data,type:区分上下移动)
    menuMoveF(node, data, type) {
      // 将变动之前的node备份
      let copyNode = { ...node };
      copyNode.previousSibling = { ...node.previousSibling };
      copyNode.nextSibling = { ...node.nextSibling };
      window.sessionStorage.setItem(
        "menuNode",
        CircularJSON.stringify(copyNode)
      );
      let nodeData = {};
      if (type === "up") {
        // 上移
        if (node.previousSibling) {
          // 删除原先的node
          this.$refs.menutree.remove(node.data);
          // 拿到copy的node
          nodeData = CircularJSON.parse(
            window.sessionStorage.getItem("menuNode")
          );
          // 复制该node到指定位置(参数:1. 要增加的节点的 data 2. 要增加的节点的后一个节点的 data、key 或者 node)
          this.$refs.menutree.insertBefore(
            nodeData.data,
            nodeData.previousSibling.data
          );
          window.sessionStorage.removeItem("menuNode");
        } else {
          this.$message.warning("该菜单已经是当前层最上级");
        }
      } else {
        // 下移
        if (node.nextSibling) {
          this.$refs.menutree.remove(node.data);
          nodeData = CircularJSON.parse(
            window.sessionStorage.getItem("menuNode")
          );
          // 参数:1. 要增加的节点的 data 2. 要增加的节点的前一个节点的 data、key 或者 node
          this.$refs.menutree.insertAfter(
            nodeData.data,
            nodeData.nextSibling.data
          );
          window.sessionStorage.removeItem("menuNode");
        } else {
          this.$message.warning("该菜单已经是当前层最下级");
        }
      }
    },
    choseUser(data) {
      this.userNodeData = data;
      this.userDialog = true;
      this.userSelection = [];
      this.$refs.userTable.clearSelection();
    },
    //选择的用户
    handleSelectionChange(val) {
      this.userSelection = val;
    },
    editUser(data) {
      this.userSelection.forEach((item) => {
        const newChild = {
          id: id++,
          label: item.userName,
          type: "RY",
        };
        data.children.push(newChild);
      });
      this.userDialog = false;
    },
  },
};
</script>

<style scoped>
.flex-box {
  display: flex;
  position: relative;
  flex-direction: column;
  height: 100%;
}
.flex-column {
  height: 100%;
}
.tree {
  position: relative;
  width: 500px;
  margin: 0.5rem 0 0 5rem;
}
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 15px;
  padding-right: 8px;
}
.remark {
  margin: 1rem 0 0 6rem;
}
.remark >>> i {
  color: #40a0ff;
}
</style>

注意

实现上移、下移功能使用了circular-json,所以需要安装一下。执行以下命令

npm i circular-json

代码都很基础,仔细看应该能看明白。

----------------------------------------❤----------------------------------------
点个赞,证明你来过~~
在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个喜欢弹吉他的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值