Function is introduced

Based on Vue. Js recursive component knowledge, to develop an uncommon tree table control. The Tree component to be implemented in this section has the following functions:

  • Nodes can extend indefinitely (recursion)
  • A node can be selected. If the parent node is selected, all its children are also selected. Similarly, if the parent node is unselected, all its children are deselected.
  • The semi-selected state of a node
  • When all child nodes of the same level are selected, their parent level is also automatically selected, until the recursive judgment is made to the root node.
  • The parent node supports expansion and contraction.

API

Table-tree is a typical data-driven component, so the node configuration is a data, which describes the information of all nodes. The data is as follows:

{" name ":" rights management ", "id" : 19, "children" : [{" id ": 58," name ":" new character ",}]}Copy the code

The configuration (props: data) of each node is described as follows:

  • Name: indicates the node title
  • Checked: Indicates whether the node is selected. After this function is enabled, the Checkbox of this object is selected.
  • Children: array of child node properties
  • Expand: Expand or shrink a node
  • Indeterminate: A node is half-selected

Entrance treeTable. Vue

Create a directory tree in SRC/Components and create two components treetable. vue and subtable. vue under the tree. Treetable. vue is the entry to the component that receives and processes data and passes it to subtable. vue; Subtable. vue is a recursive component that consists of each node, a checkbox, the node title, and the next level of the recursion.

Tree. vue does the following things:

  • Parse (json.stringify ())
  • Add the showRow attribute to terminate the recursion

The traditional tree component recursively terminates according to children, and if a node doesn’t have a children field, it’s the last node in this case, the last level of our recursion is always this

That’s going to add to the metadatashouRowattribute

// The end condition of recursion is used to determine whether the child level of the current item exists. If the child level exists, it is true. {// Add the showRow attribute for the recursive component showRow (list) {list.foreach (item => {item.showrow = this.hasthreechild (item.children) if (item.children && item.children.length ! == 0) { this.showRow(item.children); } }) }, hasThreeChild (list) { return list.some(item => item.children.length ! = = 0)}},Copy the code

Recursive component subtable.vue

Subtable. vue is the core of the treeTable component, and a subTable node contains four parts:

  • half
  • select all
  • The node title
  • Recursive child node

First look at the subTable structure

<template> <div class="permission-subTable"> <div v-if="! menu.showRow" class="content-item"> <div class="cell"> <span v-if="menu.children && menu.children.length" class="table-expand" @click="handleExpand"> <i v-if="menu.expand" class="el-icon-minus table-expand" /> <i v-else class="el-icon-plus table-expand" /> </span> <el-tooltip effect="dark" :content="menu.name " placement="right"> <el-checkbox v-model="menu.checked" class="hasEllipsis" :indeterminate="menu.indeterminate" @change="(checked) => handleCheck(checked, menu)"> {{ menu.name }} </el-checkbox> </el-tooltip> </div> <div v-show="menu.expand" class="last-content"> <template v-if="menu.children && menu.children.length"> <div v-for="child in menu.children" :key="child.id" class="last-child-item"> <el-checkbox v-model="child.checked" @change="(checked) => handleCheck(checked, child)"> {{ child.name }} </el-checkbox> </div> </template> </div> <div v-show="! menu.expand" style="flex:1; Border: 0.5 px solid # dcdfe6;" /> </div> <div v-else class="table"> <div class="title"> <el-tooltip effect="dark" :content="menu.name " placement="right"> <el-checkbox v-model="menu.checked" class="hasEllipsis" :indeterminate="menu.indeterminate" @change="(checked) => handleCheck(checked, menu)"> {{ menu.name }} </el-checkbox> </el-tooltip> </div> <div class="content"> <SubTable v-for="item in menu.children" :key="item.id" :menu="item" /> </div> </div> </div> </template> <script> export default { name: 'SubTable', props: { menu: { type: Object, default: () => ({}), }, }, data () { return { }; }, watch: { 'menu.children': { handler (data) { if (data) { if (! data.length) return; const checkedAll = ! data.some(item => ! item.checked); const menu = this.menu; this.$set(menu, 'checked', checkedAll); const isIndeterminate = data.filter(item => (item.indeterminate)); if (isIndeterminate.length) { this.$set(menu, 'indeterminate', true); } else { const checkChild = data.filter(item => (item.checked)); const indeterminate = checkChild.length < data.length && checkChild.length > 0; this.$set(menu, 'indeterminate', indeterminate); } } }, deep: true, immediate: true, }, }, mounted () { }, methods: { handleExpand () { this.$set(this.menu, 'expand', ! this.menu.expand); }, handleCheck (checked, item) { this.checkChild(checked, item); }, checkChild (checked, data) { if (data.children && data.children.length) { data.children.forEach(item => { this.checkChild(checked, item); }); } else { data.checked = checked; }}}}; </script> <style scoped lang="scss"> .table { display: flex; overflow: auto; } .title { width: 158px; display: flex; align-items: center; Border: 0.5 px solid # dcdfe6; padding: 0 4px; } .content { flex: 1; } .item-content { display: flex; } .cell { width: 158px; Border: 0.5 px solid # dcdfe6; display: flex; align-items: center; justify-content: left; padding: 0 4px; .table-expand { cursor: pointer; margin-right: 2px; } } .last-content { display: flex; flex-wrap: wrap; flex: 1; Border: 0.5 px solid # dcdfe6; max-height: 200px; overflow: auto; padding: 0 12px; } .last-child-item { flex: 40%; } .content-item { display: flex; } </style> <style lang="scss"> .permission-subTable { .hasEllipsis { .el-checkbox__label { width: 120px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; vertical-align: middle; } } } </style>Copy the code

UpdateTreeDown simply modifies all of the data downward, because the current node’s data contains all of its children, which can be easily modified by recursive traversal

Second logic is relatively complex, a node, in addition to manually selected (or against), then there is the passive selected 2 kinds of logic (or against), that is to say, if all immediate child nodes of the node (that is, it is the first level of child nodes) is selected (or against), the node is automatically selected (or against), recursively, You can go up level by level. With this idea in mind, we can use watch to monitor whether the children of the current node are selected, and then modify the current checked field:

watch: { 'menu.children': { handler (data) { if (data) { if (! data.length) return; const checkedAll = ! data.some(item => ! item.checked); const menu = this.menu; this.$set(menu, 'checked', checkedAll); const isIndeterminate = data.filter(item => (item.indeterminate)); if (isIndeterminate.length) { this.$set(menu, 'indeterminate', true); } else { const checkChild = data.filter(item => (item.checked)); const indeterminate = checkChild.length < data.length && checkChild.length > 0; this.$set(menu, 'indeterminate', indeterminate); } } }, deep: true, immediate: true, }, },Copy the code

In Watch, changes of data.children are monitored and deeply monitored. What this code means is that when a field in the data.children data changes (checked, of course), meaning that one of its children is selected (or de-selected), the logic in the bound handler is executed. const checkedAll = ! data.some(item => ! item.checked); Also a neat abbreviation, checkedAll returns the result of whether the current child nodes are all selected.

Because subtable. vue is a recursive component, there will be watch listening menu.children in each component. It should be known that the current node has two “identities”, which are both the parent node of the subordinate node and the child node of the superior node. When it is modified as the parent of the subordinate node, the watch listener function in the parent node will be triggered. That’s recursion.

Pay attention to

– Tree only knows its Github address so post it

Github.com/icarusion/v…

How does function write a traditional tree structure