feat: 文件树支持右键菜单,以及增删节点操作

This commit is contained in:
Frankie Huang 2025-04-16 01:45:53 +08:00
parent e4b5fab2fa
commit 23e3b8c15f

View File

@ -1,5 +1,12 @@
<template> <template>
<Tree ref="tree" :data="treeRenderData" :render="renderContent" expand-node></Tree> <Tree ref="tree" :data="treeRenderData" :render="renderContent" @on-contextmenu="handleContextMenu" expand-node>
<template #contextMenu>
<DropdownItem v-for="item in currentMenuNode.contextMenuData" :key="item.name"
@click="item.handler(currentMenuNode)">
{{ item.name }}
</DropdownItem>
</template>
</Tree>
</template> </template>
<script> <script>
@ -20,6 +27,16 @@ export default {
suffix: "txt", suffix: "txt",
directory: false, directory: false,
}], }],
// contextMenuData
// name handler
contextMenuData: [
{
name: "新建目录",
handler: (nodeRenderData) => {
console.log(nodeRenderData);
}
}
],
}, },
}, },
selectedNode: { selectedNode: {
@ -46,7 +63,9 @@ export default {
}, },
data() { data() {
return { return {
root: null,
treeRenderData: [], treeRenderData: [],
currentMenuNode: {},
} }
}, },
mounted() { mounted() {
@ -58,21 +77,30 @@ export default {
}, },
}, },
methods: { methods: {
// treeData // treeData treeRenderData
renderTreeByTreeData(currentTreeData) { renderTreeByTreeData(currentTreeData) {
const renderNode = this.renderNodeByNodeData(currentTreeData, 0) const renderNode = this.renderNodeByNodeData(currentTreeData, 0)
this.treeRenderData = renderNode == null ? [] : [renderNode] this.treeRenderData = renderNode == null ? [] : [renderNode]
}, },
// level nodeData 0 // level nodeData 0
renderNodeByNodeData(nodeData, level) { renderNodeByNodeData(nodeData, level) {
// null // null
if (nodeData == null || nodeData == undefined) { if (nodeData == null || nodeData == undefined) {
return null return null
} }
// input true nodeData input
if (nodeData.input === true) {
let nodeRenderData = nodeData;
nodeRenderData.input = true;
nodeRenderData.completer = nodeData.completer ?
nodeData.completer : (data, value) => {
this.$Message.error("Input Node have no completer.");
};
return nodeRenderData
}
if (nodeData.path == undefined || if (nodeData.path == undefined ||
nodeData.name == undefined || nodeData.name == undefined ||
nodeData.directory == undefined || nodeData.directory == undefined
(nodeData.directory == true && nodeData.nodes == undefined)
) { ) {
return null return null
} }
@ -98,8 +126,17 @@ export default {
path: nodeData.path, path: nodeData.path,
level: level, level: level,
} }
if (nodeData.contextMenuData && nodeData.contextMenuData.length > 0) {
// contextmenu = true
nodeRenderData.contextmenu = true
// contextMenuData
nodeRenderData.contextMenuData = nodeData.contextMenuData
}
if (nodeData.directory) { if (nodeData.directory) {
let childrenRenderData = [] if (nodeData.nodes === undefined) {
nodeData.nodes = [];
}
let childrenRenderData = [];
nodeData.nodes.forEach(node => { nodeData.nodes.forEach(node => {
const renderNode = this.renderNodeByNodeData(node, level + 1) const renderNode = this.renderNodeByNodeData(node, level + 1)
if (renderNode != null) { if (renderNode != null) {
@ -113,7 +150,46 @@ export default {
} }
return nodeRenderData return nodeRenderData
}, },
//
renderContent(h, { root, node, data }) { renderContent(h, { root, node, data }) {
// root 便
this.root = root;
// data nodeKey parentKey便
data.nodeKey = node.nodeKey;
data.parentKey = node.parent;
//
if (data.input) {
return h('span', {
style: {
display: 'inline-block',
width: '100%'
},
}, [
h('span', [
// h(resolveComponent('Input'), {
// 使 resolveComponent blur input
h('Input', {
type: 'text',
autofocus: true,
autoCorrect: "off",
spellCheck: "false",
class: 'ivu-input ivu-input-default',
style: { marginRight: '8px' },
value: data.title,
// input enter blur completer
onKeyup: (event) => {
if (event.key === "Enter") {
data.completer(data, event.target.value)
}
},
onBlur: (event) => {
data.completer(data, event.target.value)
}
}),
])
]);
}
//
return h('span', { return h('span', {
style: { style: {
display: 'inline-block', display: 'inline-block',
@ -132,9 +208,10 @@ export default {
]) ])
]); ]);
}, },
selectNode(nodeData) { //
selectNode(nodeRenderData) {
// //
if (nodeData.directory) { if (nodeRenderData.directory) {
return return
} }
@ -143,10 +220,67 @@ export default {
selectedNodes.forEach(element => { selectedNodes.forEach(element => {
element.selected = false element.selected = false
}); });
nodeData.selected = true nodeRenderData.selected = true
// //
this.$emit('file-selected', nodeData); this.$emit('file-selected', nodeRenderData);
},
//
insertTreeNode(parentRenderData, nodeData, index) {
const renderNode = this.renderNodeByNodeData(nodeData, parent.level + 1);
// renderNode null
if (renderNode == null) {
return false;
}
if (index === -1) {
parentRenderData.children.push(renderNode);
} else {
parentRenderData.children.splice(index, 0, renderNode);
}
return true;
},
//
findNodeParent(nodeRenderData) {
try {
const parentKey = this.root.find(el => el.nodeKey === nodeRenderData.nodeKey).parent;
const parent = this.root.find(el => el.nodeKey === parentKey).node;
const index = parent.children.indexOf(nodeRenderData);
return [parent, index];
} catch (err) {
console.log("find parentNode failed.");
return [null, -1];
}
},
//
appendTreeNode(parentRenderData, nodeData) {
return this.insertTreeNode(parentRenderData, nodeData, -1);
},
//
removeTreeNode(nodeRenderData) {
const [parent, index] = this.findNodeParent(nodeRenderData);
if (parent === null) {
return false;
}
parent.children.splice(index, 1);
return true;
},
//
reRenderTreeNode(nodeRenderData) {
//
const [parentRenderData, indexOfParent] = this.findNodeParent(nodeRenderData);
if (parentRenderData === null) {
return false;
}
//
if (this.removeTreeNode(nodeRenderData) === false) {
return false;
}
// 使 nodeData
return this.insertTreeNode(parentRenderData, nodeRenderData, indexOfParent);
},
// currentMenuNode 便
handleContextMenu(nodeRenderData) {
this.currentMenuNode = nodeRenderData;
}, },
} }
} }