树形结构,大多都采用递归组件完成

TreeView.vue

<template> <div class="container"> <h4>Vue.js可扩展树菜单(递归组件)</h4> <tree-menu :nodes="tree.nodes" :depth="0" :label="tree.label"></tree-menu> </div> </template> <script> import TreeMenu from "./TreeMenu"; let tree = { label: "root", nodes: [ { label: "item1", nodes: [ { label: "item1.1" }, { label: "item1.2", nodes: [ { label: "item1.2.1" } ] } ] }, { label: "item2" } ] }; export default { components: { TreeMenu }, data() { return {tree} } }; </script> <style scoped> .container { width: 300px; margin: 0 auto; text-align: left; } </style>

TreeMenu.vue

<template> <div class="tree-menu"> <div class="label-wrapper" @click="toggleChildren"> <div :style="indent" :class="labelClasses">{{ label }}</div> </div> <template v-if="showChildren"> <TreeMenu v-for="node in nodes" :key="node.label" :nodes="node.nodes" :label="node.label" :depth="depth + 1" ></TreeMenu> </template> </div> </template> <script> export default { name: "TreeMenu", props: ["nodes", "label", "depth"], data() { return { showChildren: true }; }, computed: { labelClasses() { return { "has-children": this.nodes }; }, indent() { return { transform: `translate(${this.depth * 30}px)` }; } }, methods: { toggleChildren() { this.showChildren = !this.showChildren; } } }; </script> <style scoped> .tree-menu .label-wrapper { padding: 10px 0; border-bottom: 1px solid #ccc; text-align: left; } .tree-menu .label-wrapper .has-children { cursor: pointer; } </style>

参考:https://codepen.io/anthonygore/pen/PJKNqa