[Vue entry practice] Element-UI tree component el-tree component encapsulation => implement organization tree Tree => use vue-content-menu to customize editable tree structure editableTree

Article resource link (if you need to pay, just contact me to modify): https://download.csdn.net/download/Sabrina_cc/87607289

Okay, let me make a complaint. After the company decides, the technology stack will be Vue, and I have switched from React again. fuck daddy

A good way of life is to run on the ideal road with a group of like-minded people! There is a story all the way when you look back, you have firm steps when you bow your head, and you have a clear distance when you look up.

First understand the basic Tree tree component Element-The world's most popular Vue UI framework  defined in Element-UI

Table of contents

1. Page effect preview

Second, the design of the Tree component

1. Modify the tree structure of elementUI

2. Binding attribute explanation

3. Render Tree component data

(1) Compared with the back-end interface

​(2) Call the interface to obtain the organization tree information

(3) Effect drawing of organization structure

3. Use the Tree component to realize the organization tree query list function

 1. Build the core framework of the main page

2. Display the main page list data

(1) Define query parameters in data

(2) Call interface display list data

3. Component value display data

 Fourth, realize the right-click to add and delete the organization tree

1. Install vue-context-menu

(1) Install vue-context-menu

(2) Referenced in main.js

2. Use vue-context-menu

3. Modify the organization tree

(1) el-tree adds mouse right click event

(2) Edit right-click menu function

(3) Realize the menu button function


1. Page effect preview

   Page explanation: The left side of the page contains the organization tree. After clicking the organization, the list on the right displays the personnel information list of the corresponding company. The page effect changes when you click it. You can search for the organization in the tree, and you can query the personnel account on the right , and further create, edit and delete operations.

Second, the design of the Tree component

1. Modify the tree structure of elementUI

<template>
  <div class="content">
    <div>组织列表</div>
    <el-input
      class="searchInput"
      placeholder="输入关键字进行过滤"
      v-model="filterText"
      suffix-icon="el-icon-search"
    >
    </el-input>
    <div class="treeDiv">
      <el-tree
        :data="treeData"
        :props="defaultProps"
        ref="tree"
        highlight-current
        default-expand-all
        :expand-on-click-node="false"
        @node-click="handleNodeClick"
        node-key="id"
        :current-node-key="currentNodeKey"
        :filter-node-method="filterNode"
      ></el-tree>
    </div>
  </div>
</template>
<script>
import { getOrgTreeData } from "@/api/people/people";

export default {
  data() {
    return {
      filterText: "",
      treeData: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      currentNodeKey: "",
    };
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val);
    },
  },
  created() {},
  mounted() {
    getOrgTreeData().then((res) => {
      this.treeData = res.data;
      this.currentNodeKey = res.data[0].id;
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(res.data[0].id);
      });
      this.$emit("getTreeData", res.data[0]);
    });
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    handleNodeClick(data) {
      this.$emit("getTreeData", data);
    },
  },
};
</script>

2. Binding attribute explanation

(1) :data="treeData" To bind the data corresponding to the tree structure, you need to define the treeData array in data.

data() {
    return {
      filterText: "",
      treeData: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      currentNodeKey: "",
    };
  },

(2): props="defaultProps" Configure the corresponding property names in the treeData data, which is convenient for front-end and back-end unification of property names and secondary property names

(3)  node-key="id"    for getting and setting the selected node. There are two ways to get and set: through node or through key. If you need to get or set by key, you must set it node-key.

(4)ref="tree"

(5) highlight-current Whether to highlight the currently selected node, the default value is false.

(6) Whether default-expand-all expands all nodes by default. The default value is false.

(7):expand-on-click-node="false" Whether to expand or contract the node when the node is clicked, the default value is true, if it is false, the node will be expanded or contracted only when the arrow icon is clicked.

(8) @node-click="handleNodeClick"  callback when the node is clicked

(9): current-node-key="currentNodeKey" The currently selected node, bind the custom data in data to facilitate subsequent operations

(10) :filter-node-method="filterNode"    is the method executed when filtering tree nodes. Returning true means that this node can be displayed, and returning false means that this node will be hidden.

  When the node needs to be filtered, filterthe method of the Tree instance is called, and the parameter is a keyword. It should be noted that it needs to be set at this time filter-node-method, and the value is a filter function.

3. Render Tree component data

(1) Compared with the back-end interface

 (2) Call the interface to obtain the organization tree information

mounted() {
    getOrgTreeData().then((res) => {
      this.treeData = res.data;
      this.currentNodeKey = res.data[0].id;
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(res.data[0].id);
      });
      this.$emit("getTreeData", res.data[0]);
    });
  },
// 组织机构树
export function getOrgTreeData() {
  return request({
    url: "/api/sys/organization/tree",
    method: "get",
  });
}

 (3) Effect drawing of organization structure

3. Use the Tree component to realize the organization tree query list function

renderings

 1. Build the core framework of the main page

<div class="content-panel">
          <el-col :span="6">
            <Tree @getTreeData="getTreeData"></Tree>
          </el-col>
          <el-col :span="18">
            <div class="options-panel f-r-b-c">
              <div>
                <el-input
                  v-model="params.username"
                  placeholder="请输入用户名"
                  clearable
                  style="margin-right: 30px; width: 150px"
                ></el-input>
                <el-button
                  type="primary"
                  size="mini"
                  style="margin: 34px"
                  @click="searchInfoChange"
                  >搜索</el-button
                >
                <el-button size="mini" @click="reset">重置</el-button>
              </div>
            </div>
            <div class="buttonDiv">
              <el-button type="primary" @click="createDialog">新增</el-button>
            </div>
            <div class="tableSpan">
              <el-table
                ref="singleTable"
                :data="AccountData"
                style="width: 100%"
                stripe
                fit
                highlight-current-row
                @row-click="handleClickRow"
              >
                <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
                <el-table-column
                  prop="orgName" label="公司名称" width="200" align="center"></el-table-column>
                <el-table-column prop="username" label="用户名" width="100" align="center"></el-table-column>
                <el-table-column prop="roleIds" label="权限角色" width="150" align="center" > </el-table-column>
                <el-table-column prop="status" label="状态" width="100" align="center">
                  <template slot-scope="scope">
                    <p v-if="scope.row.status == 1" type="success">启用</p>
                    <p v-if="scope.row.status == 0" type="warning">禁用</p>
                  </template>
                </el-table-column>
                <el-table-column prop="jobDuty" label="备注" width="100" align="center">
 </el-table-column>
                <el-table-column prop="" label="操作" align="center">
                  <template slot-scope="scope">
                    <el-button
                      type="text"
                      @click="handleManageRow(scope.row.id)"
                      >编辑</el-button
                    >
                    <el-button
                      @click="handleDeleteRow(scope.row.id)"
                      type="text"
                      >删除</el-button
                    >
                  </template>
                </el-table-column>
              </el-table>
              <el-pagination
                background
                class="pagelist"
                :current-page.sync="params.pageNum"
                :page-size="params.pageSize"
                layout="total, prev, pager, next"
                :total="params.total"
                @current-change="handlePageChange"
              />
            </div>
          </el-col>
        </div>

Note: The data bound to the table is: data="AccountData"

2. Display the main page list data

(1) Define query parameters in data

params: {
  username: "", // 用户名
  orgId: "", // 组织机构id
  status: "", // 状态,0:禁用,1:启用
  pageNum: 1, // 当前第几页
  pageSize: 10, // 每页数量
  total: 0, // 总记录数
},

 (2) Call interface display list data

 Looking at the interface document, it can be seen that the query needs to be performed according to the orgaId clicked in the Tree

// 获取人员账户列表
    getAccount() {
      let req = { ...this.params };
      delete req.total;
      getAccountList(req).then((res) => {
        this.AccountData = res.data.list;
        this.orgName = res.data.list[0].orgName; // 记录新建时回显的公司全部名称
        this.params.total = res.data.totalCount;
      });
    },
// account.js
// 账户详情
export function getAccountList(data) {
  return request({
    url: "api/sys/user/list",
    method: "post",
    data: data,
  });
}

3. Component value display data

Since the operation of switching the organization name is in the Tree component, but the query method getAccount() is in the parent component, so switching orgId in the child component needs to start the method @getTreedata in the parent component.

<!--父组件中引用子组件,并把方法传入子组件中-->
<Tree @getTreeData="getTreeData"></Tree>
// Tree子组件中
mounted() {
    getOrgTreeData().then((res) => {
      this.treeData = res.data;
      this.currentNodeKey = res.data[0].id;
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(res.data[0].id);
      });
      this.$emit("getTreeData", res.data[0]);
    });
  },
methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    handleNodeClick(data) {
      this.$emit("getTreeData", data);
    },
  },

Note: After obtaining the organization tree object in mounted, it needs to be initialized by default to display the list information of the first element, so the method of the parent component is called.

In handleNodeClick(), control switch and click on the organization tree, and after obtaining the organization value, call the method of the parent component to query and display the data

getTreeData(data) {
      this.params.orgId = data.id; // 获取选中的组织树的机构id
      this.treeNodeData = data;
      this.getAccount();
      }
    },

 Fourth, realize the right-click to add and delete the organization tree

1. Install vue-context-menu

Reference link: vue-context-menu mouse right button event_poplargg's blog-CSDN blog_vue-context-menu

(1) Install vue-context-menu

npm install vue-contextmenu --save

(2) Referenced in main.js

import VueContextMenu from 'vue-contextmenu'
Vue.use(VueContextMenu)

2. Use vue-context-menu

<div class="treeDiv">
      <el-tree
        :data="treeData"
        :props="defaultProps"
        ref="tree"
        highlight-current
        default-expand-all
        :expand-on-click-node="false"
        @node-click="handleNodeClick"
        node-key="id"
        :current-node-key="currentNodeKey"
        :filter-node-method="filterNode"
        @node-contextmenu="showMenu"
      ></el-tree>
      <vue-context-menu
        :contextMenuData="contextMenuData"
        @handleNew="handleNew"
        @handleDelete="handleDelete"
      ></vue-context-menu>
    </div>

Bind and add contentMenuData in data. menuName-menu name, axis-position coordinates, menulist-menu options (corresponding methods) are fixed writing.

data() {
    return {
      filterText: "",
      treeData: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      currentNodeKey: "",
      currentNodeNode: {},
      // 菜单数据
      contextMenuData: {
        menuName: "demo",
        //菜单显示的位置
        axis: {
          x: null,
          y: null,
        },
        //菜单选项
        menulists: [
          {
            fnHandler: "handleNew", //绑定事件
            btnName: "新增", //菜单名称
          },
          {
            fnHandler: "handleDelete",
            btnName: "删除",
          },
        ],
      },
      dialogFormVisible: false,
      form: {
        type: 1,
        name: "",
        creditCode: "",
        contactName: "",
        contactPhone: "",
      },
      formLabelWidth: "100px",
    };
  },

3. Modify the organization tree

(1) el-tree adds mouse right click event

Among them, @node-contextmenu="showMenu" will trigger this event when a node is right-clicked  

showMenu(event, data) {
      console.log(data);
      this.currentNodeNode = data;
      this.$refs.tree.setCurrentKey(data.id);
      this.currentNodeKey = data.id;
      event.preventDefault();
      var x = event.clientX;
      var y = event.clientY;
      // Get the current location
      this.contextMenuData.axis = {
        x,
        y,
      };
    },

Its main purpose is to display the menu at the position where the mouse is right-clicked, and obtain the information of the clicked organization tree.

(2) Edit right-click menu function

The right-click menu contains two functions [New] and [Delete] corresponding to handleNew and handleDelete respectively, and the content of this part is defined in the menuists menu option in contextMenuData.

<vue-context-menu
    :contextMenuData="contextMenuData"
    @handleNew="handleNew"
    @handleDelete="handleDelete"
></vue-context-menu>
//菜单选项
 menulists: [
   {
      fnHandler: "handleNew", //绑定事件
      btnName: "新增", //菜单名称
   },
   {
      fnHandler: "handleDelete",
      btnName: "删除",
   },
],

(3) Realize the menu button function

New: Show popup

// 新建 - 弹框
handleNew() {
      this.dialogFormVisible = true;
},

Delete: Call the interface to delete nodes in the organization tree

handleDelete() {
      this.$confirm("此操作将永久删除该组织, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          deleteOrg(this.currentNodeKey).then((res) => {
            if (res.code === 200 && res.success === true) {
              this.$message.success(res.message);
              this.getTreeData();
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },

Guess you like

Origin blog.csdn.net/Sabrina_cc/article/details/121701526