Encapsulate the Tree component with the right-click menu

Tree.vuefile

<template>
  <div class="tree-container">
    <! Lazy ="true" -->

    <el-tree
      class="_tree"
      :data="treeList"
      :props="defaultProps"
      @node-expand="handleNodeExpand"
      @node-click="handleNodeClick"
      @node-contextmenu="handleRightClick"
      :default-expanded-keys="expandedKeys"
      :node-key="nodeKey"
      :highlight-current="true"
      ref="comnTree"
      :style=" `max-height:${treeHeight}px; max-width:${treeWidth}px; overflow-x:auto; } `"
    >
      <span slot-scope="{ node, data }">
        <i :class="data.icon ? data.icon : 'el-icon-folder-opened'"></i>
        <span class="tree_label">{{ node.label }}</span>
        <span
          class="tree_label"
          v-if="data.total || data.total === 0"
          title="The number"
          >({{ data.total }})</span
        >
      </span>
    </el-tree>

    <el-popover
      placement="right"
      width="150"
      trigger="manual"
      v-model="Flag"
      class="popover-intree"
      id="contextMenu"
      :style="`left:${clientX}px; top:${clientY}PX`"
    >
      <ul>
        <li
          v-for="item in contextMenu"
          :key="item.id"
          class="context-menu"
          @click="handleClickMenu(item)"
        >
          {{ item.name }}
        </li>
      </ul>
    </el-popover>
  </div>
</template>
<script>
import { getViewHeight } from "@/utils/getViewHeight.js";
export default {
  data() {
    return {
      clientX: "".clientY: ""
    };
  },
  props: {
    treeList: {
      type: Array
    },
    defaultProps: {
      type: Object.default() {
        return {
          children: "children".label: "name"
          // isLeaf: "leaf" // page that needs a leaf node}; }},nodeKey: {
      // Each tree node is used as a unique identifier. The entire tree should be unique
      type: String.default() {
        return "menuId"; }},contextMenu: {
      type: Array.default() {
        let menu = [
          {
            name: "Add".value: "add"
          },
          {
            name: "Change".value: "edit"
          },
          {
            name: "Delete".value: "del"}];// Tree right-click menu
        returnmenu; }},rightFlag: {
      type: Boolean.default() {
        return false; }},treeHeight: {
      type: Number.default() {
        return getViewHeight() - 200; }},treeWidth: {
      type: Number.default() {
        return 237; }},expandedKeys: {
      // The default expanded tree node, ids
      type: Array.default() {
        return[]; }}},computed: {
    Flag: {
      get() {
        return this.rightFlag;
      },
      set(val) {
        this.$emit("updateTreeMenu", val); }}},mounted() {
    // Listen, except click yourself, click somewhere else to hide itself
    window.addEventListener("click".this.handleClickDoc);
  },
  methods: {
    handleNodeClick(data) {
      this.$emit("updateTreeMenu".false); // Hide the right-click menu when clicking on a tree node.
      this.$emit("handleNodeClick", data);
    },
    handleRightClick(event, obj, node, self) {
      // Determine where the right-click menu appears
      this.clientX = event.offsetX;
      this.clientY = event.clientY; // The height should be adjusted according to your layout
      this.setCurrTreeNode(obj[this.nodeKey]);
      this.$emit("handleRightClick", obj);
    },
    handleClickMenu(item) {
      this.$emit("handleClickTreeMenu", item);
    },
    handleNodeExpand(data, node, self) {
      this.$emit("handleNodeExpand", data);
    },
    // Select the method of tree node. When the id is modified, the child component can not listen to the change of the id passed by the parent component. The parent component can take the method of actively obtaining the child component to realize the active selection of the tree node after modification.
    setCurrTreeNode(id) {
      this.$refs["comnTree"].setCurrentKey(id);
    },
    handleClickDoc(e) {
      const contextMenu = document.getElementById("contextMenu");
      if(! contextMenu)return; ! contextMenu.contains(e.target) &&this.$emit("updateTreeMenu".false); }},beforeDestroy() {
    window.removeEventListener("click".this.handleClickDoc); }}};</script>
<style lang="scss">
.tree-container {
  position: relative;

  ._tree {
    color: # 444;
    padding-left: 6px;
    overflow: auto; // Change the default icon color of the tree, whether the icon is a leaf node or not //span {
    //   color: $icon_color; / / / /}.is-leaf {
    //   color: transparent;
    // }
    .tree_label {
      font-size: 14px;
      letter-spacing: 1px;
      margin-left: 5px; }}.popover-intree {
    position: absolute;
    ul {
      padding: 3px;
    }
    li {
      list-style: none; }}.context-menu {
    letter-spacing: 1px;
    color: # 222;
    cursor: pointer;
    height: 30px;
    line-height: 30px;
    color: # 000;
    text-align: center;
    &:hover {
      border-radius: 2px;
      background: #648fdb;
      color: #fff; }}.el-popover {
    padding: 2px;
    min-width: 20px;
    border: 1px solid #ebeef5;
    border-radius: 0;
    box-shadow: 4px 4px 4px -4px rgb(121.118.118); } // Override the active style of tree.el-tree--highlight-current
    .el-tree-node.is-current
    > .el-tree-node__content {
    background: $active_color;
    color: #fff; } // Override the tree style to make the landscape beyond the display scrollbar.el-tree > .el-tree-node {
    min-width: 100%;
    display: inline-block; }}</style>

Copy the code

2. Introduce and use the Tree component that you just encapsulated

  1. :treeList=”treeList” Binding tree menu list
  2. :contextMenu=”contextMenu” right-click menu
  3. :rightFlag=”rightFlag” Whether to display the right menu
  4. @handlenodeclick =”handleNodeClick” binding tree node is clicked, triggered function;
  5. @handlerightclick =”handleRightClick” binds a function triggered by right-clicking on a tree node
  6. @handlecLickTreemenu =”handleClickTreeMenu” bind the function triggered by right click menu
  7. @updateTreeMenu="updateTreeMenu"Bound to changerightFlagWhen, the triggered function

Test. The vue file

<template>
  <div>
    <my-tree
      :treeList="treeList"
      :rightFlag="rightFlag"
      :defaultProps="defaultProps"
      :nodeKey="nodeKey"
      @handleNodeClick="handleNodeClick"
      @handleRightClick="handleRightClick"
      @handleClickTreeMenu="handleClickTreeMenu"
      @updateTreeMenu="updateTreeMenu"
    ></my-tree>
  </div>
</template>
<script>
import myTree from "@/components/Tree.vue"; // Introduce the tree.vue component just defined under SRC/Components
export default {
  components: {
    myTree
  },
  data() {
    return {
      treeList: [
        // Usually from the background
        {
          mid: "1".mName: "qqq".subs: [{mid: "2".mName: "aaaa"}}]].rightFlag: false.// Whether to display the right-click menu
      defaultProps: {
        // Define the display properties. In treeList are subs and mName,
        children: "subs".label: "mName"
      },
      nodeKey: "mid" // The unique flag of the tree, mid, is also the unique flag of each column in the treeList
    };
  },
  methods: {
    updateTreeMenu(val) {
      this.rightFlag = val;
    },
    handleNodeClick(data) {
      console.log("Tree node is clicked:", data);
    },
    handleRightClick(obj) {
      this.rightFlag = true; // Displays the right-click menu
      console.log("Right mouse click on the node", obj);
    },
    handleClickTreeMenu(item) {
      alert(item.name);
      this.rightFlag = false; }}};</script>
Copy the code

GetViewHeight:

Getviewheight.js gets the current viewport height

export function getViewHeight() {
  let winHeight = 0;
  if (window.innerHeight) {
    winHeight = window.innerHeight;
  } else if (document.body && document.body.clientHeight) {
    winHeight = document.body.clientHeight;
  }else 
  if (document.documentElement && document.documentElement.clientHeight) {
    winHeight = document.documentElement.clientHeight;
  }
  return winHeight;
}
Copy the code

The content of props can be determined as required. The final effect is shown in the figure below: