vue怎么实现文件树
Vue 实现文件树的方法
使用递归组件实现文件树
递归组件是Vue中实现文件树的常见方法。通过组件自身调用自身,可以处理嵌套的目录结构。
<template>
<div>
<ul>
<tree-node
v-for="node in treeData"
:key="node.id"
:node="node"
></tree-node>
</ul>
</div>
</template>
<script>
import TreeNode from './TreeNode.vue'
export default {
components: {
TreeNode
},
props: {
treeData: {
type: Array,
required: true
}
}
}
</script>
TreeNode组件实现:
<template>
<li>
<div @click="toggle">
{{ node.name }}
<span v-if="hasChildren">[{{ isOpen ? '-' : '+' }}]</span>
</div>
<ul v-show="isOpen" v-if="hasChildren">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
></tree-node>
</ul>
</li>
</template>
<script>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
}
},
data() {
return {
isOpen: false
}
},
computed: {
hasChildren() {
return this.node.children && this.node.children.length
}
},
methods: {
toggle() {
if (this.hasChildren) {
this.isOpen = !this.isOpen
}
}
}
}
</script>
使用第三方库
Vue生态中有专门的文件树组件库,如vue-json-tree-view或vue-tree-list,可以快速实现功能丰富的文件树。

安装vue-tree-list:
npm install vue-tree-list --save
基本用法:

<template>
<vue-tree-list
:model="treeData"
@click="onClick"
></vue-tree-list>
</template>
<script>
import { VueTreeList, Tree, TreeNode } from 'vue-tree-list'
export default {
components: {
VueTreeList
},
data() {
return {
treeData: new Tree([
{
name: 'Node 1',
children: [
{
name: 'Node 1-1',
isLeaf: true
},
{
name: 'Node 1-2'
}
]
},
{
name: 'Node 2'
}
])
}
},
methods: {
onClick(params) {
console.log(params)
}
}
}
</script>
动态加载文件树数据
对于大型文件系统,可以实现懒加载功能,当用户展开节点时才加载子节点数据。
<template>
<div>
<ul>
<tree-node
v-for="node in treeData"
:key="node.id"
:node="node"
@load-children="loadChildren"
></tree-node>
</ul>
</div>
</template>
<script>
import TreeNode from './TreeNode.vue'
export default {
components: {
TreeNode
},
data() {
return {
treeData: []
}
},
methods: {
loadChildren(node) {
// 调用API获取子节点数据
fetch(`/api/nodes/${node.id}/children`)
.then(response => response.json())
.then(children => {
this.$set(node, 'children', children)
})
}
}
}
</script>
TreeNode组件相应调整:
<template>
<li>
<div @click="toggle">
{{ node.name }}
<span v-if="!isLeaf">[{{ isOpen ? '-' : '+' }}]</span>
</div>
<ul v-show="isOpen" v-if="!isLeaf">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
@load-children="$emit('load-children', child)"
></tree-node>
</ul>
</li>
</template>
<script>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
}
},
data() {
return {
isOpen: false
}
},
computed: {
isLeaf() {
return !this.node.children
}
},
methods: {
toggle() {
if (!this.isLeaf) {
this.isOpen = !this.isOpen
if (this.isOpen && (!this.node.children || this.node.children.length === 0)) {
this.$emit('load-children', this.node)
}
}
}
}
}
</script>
添加交互功能
文件树通常需要支持多种交互,如选择、拖拽、右键菜单等。可以通过扩展基础组件实现这些功能。
<template>
<li
:class="{ 'selected': isSelected }"
@click="select"
@contextmenu.prevent="showContextMenu"
draggable="true"
@dragstart="dragStart"
@dragover.prevent
@drop="drop"
>
<div @click.stop="toggle">
{{ node.name }}
<span v-if="!isLeaf">[{{ isOpen ? '-' : '+' }}]</span>
</div>
<ul v-show="isOpen" v-if="!isLeaf">
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
@select-node="$emit('select-node', $event)"
@context-menu="$emit('context-menu', $event)"
@node-drag-start="$emit('node-drag-start', $event)"
@node-drop="$emit('node-drop', $event)"
></tree-node>
</ul>
</li>
</template>
<script>
export default {
// ...其他代码
methods: {
select() {
this.$emit('select-node', this.node)
},
showContextMenu(event) {
this.$emit('context-menu', { node: this.node, event })
},
dragStart(event) {
this.$emit('node-drag-start', { node: this.node, event })
},
drop(event) {
this.$emit('node-drop', { targetNode: this.node, event })
}
}
}
</script>
<style>
.selected {
background-color: #e0f7fa;
}
</style>






