element-ui树形组件实现懒加载、右键新增、右键删除、右键编辑,以及拖拽更换节点

<template>
  <el-card shadow="never" class="aui-card--fill">
    <div class="tree-box">
      <div class="tree-title">
        <el-input placeholder="输入关键字进行过滤" v-model.trim="tree.filterText" size="small"></el-input>
      </div>
      <div class="tree-content" v-loading="tree.loading">
        
        <div v-if="position=='page'" style="position:relative">
          <span style="position:absolute;z-index:2;top:6px;right:3px;font-size:12px;color:#9c9b9b">(右键可编辑视频树形分类)</span>
        </div>
        <el-tree
          class="filter-tree"
          :load="loadNode"
          lazy
          :draggable="$hasPermission('video:video-manage:dragclass')"
          @node-expand="handleNodeExpand"
          @node-collapse="handleNodeCollapse"
          :default-expanded-keys="tree.expandedKeys"
          node-key="id"
          :highlight-current="highlightCurrent"
          :props="tree.defaultProps"
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          @node-click="hadleNodeClick"
          @node-contextmenu="rihgtClick"
          @node-drop="handleDrop"
          :allow-drop="allowDrop"
          :allow-drag="allowDrag"
          ref="tree"
        ></el-tree>
        <div v-show="menuVisible" id="rightClickMenu">
          <ul class="menu-list">
            <li>
              <el-button
                type="text"
                size="small"
                @click="NodeConfig('add')"
                v-if="$hasPermission('video:video-manage:addclass')"
              >新增子分类</el-button>
            </li>
            <li>
              <el-button
                type="text"
                size="small"
                :disabled="DATA&&DATA.id=='1270550715957256193'"
                @click="NodeDel()"
                v-if="$hasPermission('video:video-manage:deleteclass')"
              >删除分类</el-button>
            </li>
            <li>
              <el-button
                type="text"
                size="small"
                 :disabled="DATA&&DATA.id=='1270550715957256193'"
                @click="NodeConfig('edit')"
                v-if="$hasPermission('video:video-manage:editclass')"
              >编辑分类</el-button>
            </li>
          </ul>
        </div>
      </div>
    </div>
    <videoConfig ref="videoConfig" @updateTree="updateTree" />
  </el-card>
</template>
<script>
import videoConfig from "@/components/video/model-videoClass-config";
import debounce from "lodash/debounce";
export default {
  name: "",
  components: {
    videoConfig,
  },
  props: {
    currentKey: {
      type: String,
      default: "",
    },
    position: {
      type: String,
      default: "page",
    },
    isSelect: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      configType: "",
      menuVisible: false,
      objectID: "",
      DATA: null,
      VALUE: null,
      highlightCurrent: true,
      tree: {
        data: [],
        expandedKeys: ['1270550715957256193'],/**设置默认展开的节点,此时必须设置node-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。 */
        node: null,
        resolve: null,
        loading: false,
        filterText: "",
        defaultProps: {
          children: "children",
          label: "name",
          isLeaf: "isLeaf",
        },
      },
    };
  },
  watch: {
    "tree.filterText"(val) {
      this.$refs.tree.filter(val);
    },
  },
  computed: {
    dataRule() {
      return {
        name: [
          {
            required: true,
            message: this.$t("validate.required"),
            trigger: "blur",
          },
        ],
      };
    },
    enabledConfig() {
      return (
        this.$hasPermission("video:video-manage:addclass") ||
        this.$hasPermission("video:video-manage:editclass") ||
        this.$hasPermission("video:video-manage:deleteclass")
      );
    },
  },
  created() {},
  mounted() {},
  methods: {
    //懒加载
    async loadNode(node, resolve) {
      if (node.level === 0) {
        this.tree.node = node;
        this.tree.resolve = resolve;
        let rootData = [
          { id: "1270550715957256193", name: "视频分类", parentId: null ,children:[]},
        ];
        this.tree.expandedKeys = [rootData[0].id];
        resolve(rootData);
        this.$nextTick(() => {
          this.$refs["tree"].setCurrentKey("1270550715957256193");
          this.$emit("updateTreeItem", rootData[0]);
        });
      } else {
        let ndoeData = await this.loadTreeData(node.data.id);
        resolve(ndoeData);
      }
      if (this.currentKey) {
        this.reShowHighlight();
      }
    },
    //高亮其中一项
    reShowHighlight() {
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(this.currentKey);
      });
    },
    //加载树形数据
    loadTreeData(parentId) {
      return new Promise((resolve, reject) => {
        this.$http
          .get("/vod/mrcategory/list", {
            params: {
              parentId: parentId,
              selectChildList: 0,
            },
          })
          .then(({ data: res }) => {
            resolve(res.data);
          })
          .catch((er) => {
            reject(er);
          });
      });
    },
    // 搜索
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    // 右击
    rihgtClick(event, object, node, element) {
      if (
        this.position === "modal" ||
        !(
          this.$hasPermission("video:video-manage:addclass") ||
          this.$hasPermission("video:video-manage:editclass") ||
          this.$hasPermission("video:video-manage:deleteclass")
        )
      ) {
        return;
      }

      if (this.objectID !== object.id) {
        this.objectID = object.id;
        this.menuVisible = true;
        this.DATA = object;//该节点所对应的对象
        this.NODE = node;//该节点所对应的node
        const parent = this.NODE.parent;
        // this.$refs.tree.append(({ name: this.dataForm.name }, object));
      } else {
        this.menuVisible = !this.menuVisible;
      }
      document.addEventListener("click", (e) => {
        this.menuVisible = false;
      });
      let menu = document.querySelector("#rightClickMenu");
      /* 菜单定位基于鼠标点击位置 */
      menu.style.left = event.offsetX + 50 + "px";
      menu.style.top = event.offsetY + 50 + "px";
      // menu.style.left = event.clientX + 30 + "px";
      // menu.style.top = event.clientY + 30 + "px";
    },
    // 点击树的item
    hadleNodeClick(data, node) {
      this.menuVisible = false;
      if (
        this.position == "modal" &&
        data.name == "视频分类" &&
        this.isSelect
      ) {
        this.highlightCurrent = false;
        this.$emit("updateTreeItem", {
          id: "",
          name: "",
          parentId: null,
        });
      } else {
        this.highlightCurrent = true;
        this.$emit("updateTreeItem", data);
      }
    },
    // 树展开某一节点的时候
    handleNodeExpand(data, node, ele) {
      this.$set(ele, "expanded", true);
      if (node.expanded) {
        this.tree.expandedKeys.push(data.id);
        this.tree.expandedKeys = Array.from(new Set(this.tree.expandedKeys));//去重
      }
    },
    // 树关闭某一节点的时候
    handleNodeCollapse(data, node, ele) {
      let index = this.tree.expandedKeys.findIndex((item) => item === data.id);
      if (index !== -1) {
        this.tree.expandedKeys.splice(index, 1);
      }
      this.$set(ele, "expanded", false);//需要手动折叠当前节点
    },
    NodeConfig(type) {
      this.configType = type;
      if (type === "add") {
        this.$refs.videoConfig.initModal({ parentId: this.DATA.id });
      } else {
        let data = JSON.parse(JSON.stringify(this.DATA));
        this.$refs.videoConfig.initModal(data);
      }
    },
    //新增或者编辑的回调
    updateTree(data) {
      if (this.configType === "edit") {
        this.$set(this.DATA, "name", data.name);
      } else {
        if (!this.DATA.children) {
          this.$set(this.DATA, "children", []);
        }
        this.$nextTick(() => {
          this.DATA.children.push(data);
        });
      }
    },
    //删除
    NodeDel() {
      this.$confirm(
        this.$t("prompt.info", { handle: this.$t("delete") }),
        this.$t("prompt.title"),
        {
          confirmButtonText: this.$t("confirm"),
          cancelButtonText: this.$t("cancel"),
          type: "warning",
        }
      )
        .then(() => {
          this.$http
            .delete("/vod/mrcategory", {
              data: [this.DATA.id],
            })
            .then(({ data: res }) => {
              if (res.code !== 0) {
                return this.$message.error(res.msg);
              }
              this.$message({
                message: this.$t("prompt.success"),
                type: "success",
                duration: 500,
                onClose: () => {
                  // let node = this.$refs.tree.getNode(this.DATA.parentId);
                  // node.loaded = false;
                  // node.expand();
                  // const parent = this.NODE.parent;
                  // const children = parent.data.children || parent.data;
                  // const index = children.findIndex(d => d.id === this.DATA.id);
                  // children.splice(index, 1);
                  this.$refs.tree.remove(this.NODE);
                },
              });
            })
            .catch(() => {});
        })
        .catch(() => {});
    },
    //拖拽执行的更新方法
    handleDrop(draggingNode, dropNode, dropType, ev) {
      this.$http["put"]("/vod/mrcategory", {
        name: draggingNode.data.name,
        id: draggingNode.data.id,
        parentId:
          dropType === "inner" ? dropNode.data.id : dropNode.data.parentId,
      })
        .then(({ data: res }) => {
          if (res.code !== 0) {
            return this.$message.error(res.msg);
          }
          this.$message({
            message: this.$t("prompt.success"),
            type: "success",
            duration: 500,
            onClose: () => {},
          });
        })
        .catch(() => {});
    },
    //允许被扔放的节点
    allowDrop(draggingNode, dropNode, type) {
      return dropNode.data.id !== "1270550715957256193";
      // if (dropNode.data.id === "1270550715957256193") {
      //   return type !== "before";
      // } else {
      //   return true;
      // }
    },
    //允许拖拽的节点
    allowDrag(draggingNode) {
      return draggingNode.data.id !== "1270550715957256193";
    },
  },
  destroyed() {},
};
</script>
<style lang='scss'>
#video-manage {
  .el-tree__empty-block{
    margin-top: 100px;
  }
  .tree-box {
    .tree-title {
      margin-bottom: 10px;
    }
    .tree-content {
      height: calc(100vh - 50px - 38px - 30px - 40px - 42px);
      overflow: auto;
       &::-webkit-scrollbar {
        width: 6px;
        height: 6px;
      }
      &::-webkit-scrollbar-track {
        background: #f1f1f1;
        border-radius: 8px;
      }
      &::-webkit-scrollbar-track-piece {
        /*内层轨道,滚动条中间部分(位置4)*/
        border-radius: 2px 2px 0px 0px;
      }
      &::-webkit-scrollbar-thumb {
        background: #c1c1c1;
        border-radius: 6px;
      }
      &::-webkit-scrollbar-thumb:hover {
        background: #aba8a8;
      }
      &::-webkit-scrollbar-corner {
        background: #f6f6f6;
      }
     
        
      #rightClickMenu {
        background: #fff;
        position: absolute;
        z-index: 3;
        transform-origin: left center;
        width: 100px;
        height: 150px;
        padding: 10px;
        border-radius: 5px;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        ul {
          li {
            .el-button {
              width: 100%;
              text-align: left;
            }
          }
        }
      }
    }
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值