The cause of
The thing is, there’s been a demand on the project recently. The server has an image space, which is basically a folder. You know the structure of the folder, layer by layer. And then you need a tree at the front.
The specific requirements are as follows
- You can create subdirectories, but you can only create second, third, new button is disabled.
- To display the parent directory name and current path on the page, use
'/'
Space. - The root directory is fixed to image space.
- When the page is opened for the first time, the interface is requested and only the level 1 directory is returned. By default, all level 1 directories are displayed.
- The user clicks on the level 1 directory, according to the click level 1 directory corresponding to
id
The request interface returns the secondary directory, and so on.
When I saw this requirement, I thought to myself, I’ve seen this on the ElementUI website, good. It turned out that when I went to develop it, it was quite complicated, so I spent some time researching it in case I forgot to use it next time.
To deal with
Let’s copy the official elementUI example. And then I added something random.
<template>
<div>
<el-input v-model="input"
style="width:200px"
placeholder="Please enter content"></el-input>
<el-button type="primary">Add a node</el-button>
<span>Current directory:</span>
<span>Parent directory of the current directory:</span>
<el-tree :data="data"
:props="defaultProps"
accordion
@node-click="handleNodeClick"></el-tree>
</div>
</template>
<script>
export default {
data() {
return {
input: ' '.data: [{
label: 'Picture Space'.children: [{
label: 'vegetables'.children: [{
label: 'spinach'}, {label: 'lettuce',},],}, {label: 'fruit'.children: [{
label: 'banana',}],}, {label: 'beauty'.children: [{
label: 'Qin Lan',}],}],}],defaultProps: {
children: 'children'.label: 'label',}}; },methods: {
handleNodeClick(data) {
console.log(data); ,}}};</script>
Copy the code
Now the interface looks like this.
Demand a
Let’s start with the simplest. Add a category (child node) to any directory.
Then we go and see what the documentation says. Well, this is it.
Receive two parameters (data, parentNode)
- Of the child node to be appended
data
- The child nodes of the
parent
的data
,key
ornode
The first parameter, data, is just a name in the current example. How do I get the second parameter that I want to pass?
To add a child node to a directory, you have to click on the directory first, so let’s see what click events give us back.
You can see that the second callback parameter is the node corresponding to the node, so there you have it! So give it a try.
When we click on a node, the node callback is stored in the nowClickNode variable. When we call append, we pass nowClickNode to it.
// To save space, omit the code in the template and post the whole code at the end
methods: {
// Click the node
handleNodeClick(nodes, node, self) {
this.nowClickNode = node;
},
// Add a node
addSort() {
const data = {
label: 'strawberry'};this.$refs.tree.append(data, this.nowClickNode); }},Copy the code
Success!
NowClickNode: nowClickNode: nowClickNode: nowClickNode: nowClickNode: nowClickNode: nowClickNode This variable has a level attribute, which represents the level. I do this by calculating properties.
//template
<el-button type="primary"
:disabled='isDisabled'
@click='addSort'> Add a node </el-button>//js
computed: {
// Whether to create a new category
isDisabled() {
if (this.nowClickNode.level > 2) {
return true;
}
return false; }},Copy the code
You can see that the button is disabled when we hit level three.
Demand for two
Next we implement the second requirement, showing the current path and parent directory. Just look at the one above for this example. It’s already implemented.
// Triggers an event when a node is clicked
handleNodeClick(nodes, node, self) {
this.nowClickNode = node;
this.nowPathArr = [];
// If not the root node
if (node.parent.parent) {
this.faterName = node.parent.data.label;
// Find the path recursively
this.findParentName(node);
// Splice paths
this.nowPath = 'Picture space /The ${this.nowPathArr.join('/')}`;
} else {
// Assign a value directly to the root node
this.nowPath = 'Picture Space';
this.faterName = '-'; }},// Find the class name of the parent node
findParentName(node) {
if (node.parent.parent) {
this.nowPathArr.unshift(node.data.label);
this.findParentName(node.parent); }},Copy the code
My root directory also has the parent attribute, so I have to go up one level to see if parent. Parent exists.
What I’m doing is I’m recursively looking for the parent element of the node that I clicked on, and then I’m putting all the ancestors in the array, and THEN I’m splicing.
Three, four, five
The remaining three requirements are put together. In this place, I used the real data of the project when I practiced, which is not convenient to demonstrate. The code is also desensitized. The important thing is to know how to use it.
//template
<el-tree
:data="treeData" / / the data source
:props="defaultProps" / / configuration items
accordion // Open accordion mode one node at a time
ref="tree" // To get the DOM
lazy // The node is loaded lazily
:highlight-current='true' // Highlight the current node
:load='treeLoad' // The method called during lazy loading
node-key="cateId" // Unique identifier
:default-expanded-keys='defaultOpen' // The array of nodes opened by default
:expand-on-click-node='true' // Whether to expand or shrink a node when clicked. The default value is true. If false, the node will be expanded or shrunk only when the arrow icon is clicked.
@node-click="handleNodeClick" // Click the callback function of the node
>
</el-tree>
//js
// The load tree is the function that lazily loads the binding
treeLoad(node, resolve) {
// Determine the node level
if (node.level == 0) {
// If it is the root node, add a fixed image space node
resolve([{
cateName: 'Picture Space'.cateId: '0'.children: [],}]); }// Not the root node, fetch the interface load list here to realize the need for four, five tree structure lazy load, click the end of the level request level data
if (node.level >= 1) {
this.getCategoryListNew(node, resolve);
// Prevent the loading animation from appearing all the time when the child node is empty
returnresolve([]); }},// Call the resolve method after data is processed
getCategoryListNew(node, resolve) {
Service.getCategoryListNew({ parentId: node.data.cateId }).then(({ data }) = > {
resolve(data);
}).catch((e) = > {
console.log(e);
});
},
Copy the code
Other knowledge points
Note a few points of knowledge
Default expansion node
The default expansion is default-expanded-keys=’defaultOpen’. DefaultOpen stores an array of Node-keys.
Horizontal and longitudinal scroll bars
First, add width and height to the outer layer of the Tree component, as well as overflow properties. Then you need to modify the properties of el-Tree.
.tree-box{
width: 200px;
height: calc(100% - 30px);
overflow:auto;
}
.el-tree {
display: inline-block;
min-width: 100%;
}
Copy the code
Refreshes a node
// Find the corresponding tree node object by node ID
const node = this.$refs.tree.getNode(this.nodeId);
// Set loaded to false to tell the tree that the node was not loaded
node.loaded = false;
// Call the expand node method to query all child nodes under this node
node.expand();
Copy the code
Simulate clicking on the first node in the level 1 directory
/ / select the dom
const root = document.querySelector('.el-tree-node__children');
// Find the target node
const firstNode = root.firstChild;
// Simulate the click
firstNode.click();
Copy the code