Vue.js 递归组件实战:从零构建树形菜单与树形表格

作者:青团子

时间:2026-10-30

浏览:306

本文详解Vue.js中递归组件的核心机制,重点讲解通过name属性实现组件自我调用的方法。通过模拟数据与完整代码示例,演示如何构建支持无限层级嵌套的树形菜单,并展示如何在此基础上扩展实现树形表格功能,帮助开发者掌握复杂UI组件的开发技巧。

文章目录

递归组件基础概念

递归组件

在Vue中,组件可以在其模板内部递归调用自身,但前提是必须定义name选项。这是实现递归组件的关键约束,因此定义组件时务必包含name属性。基于这一原则,我们开始具体实现。

树形菜单实现步骤

最终实现的界面效果如下所示:

递归组件基础概念    

模拟的数据结构格式如下:


var data = [{
        "id": "1",
        "data": {
          "menuName": "项目管理",
          "menuCode": "",
        },
        "childTreeNode": [{
          "data": {
            "menuName": "项目",
            "menuCode": "BusProject",
          },
          "childTreeNode": []
        }, {
          "data": {
            "menuName": "我的任务",
            "menuCode": "BusProject",
          },
          "childTreeNode": []
        }, {
          "data": {
            "menuName": "人员周报",
            "menuCode": "BusProject",
          },
          "childTreeNode": []
        }]
      }, {
        "id": "2",
        "data": {
          "menuName": "数据统计",
          "menuCode": "BusClock",
        },
        "childTreeNode": []
      }, {
        "id": "3",
        "data": {
          "menuName": "人事管理",
          "menuCode": "",
        },
        "childTreeNode": []
      }, {
        "id": "4",
        "data": {
          "menuName": "基础管理",
          "menuCode": "",
        },
        "childTreeNode": []
      }]

HTML结构的实现思路是在ul标签内嵌套li标签,形成无限层级的ul套li结构,标题部分则使用div元素进行包裹。


<li>
  <div @click='toggle'>
  
     <i v-if='isFolder' class="fa " :class="[open?'fa-folder-open':'fa-folder']"></i>
     <!--isFolder判断是否存在子级改变图标-->
     <i v-if='!isFolder' class="fa fa-file-text"></i> {{model.data.menuName}}
   </div>
   <ul v-show="open" v-if='isFolder'>
     <items v-for='cel in model.childTreeNode' :model='cel'></items>
   </ul>
 </li>

官方文档明确指出,实现递归组件必须使用name属性。


export default {
  name: 'items',
  props: ['model'],
  components: {},
}

遵循Vue不直接操作DOM树的理念,我们定义了两个数据变量:open用于控制子菜单的显示与隐藏,isFolder用于标识是否存在子菜单以切换图标样式。


data() {
    return {
       open: false,
       isFolder: true
    }
}

利用Vue的计算属性动态计算isFolder的值,从而修改图标显示。该属性通过判断是否存在子级以及子级的长度来确定状态。


computed: {
  isFolder() {
    return this.model.childTreeNode && this.model.childTreeNode.length
  }
}    

接下来处理显示与隐藏的交互事件。


methods: {
  toggle: function() {
   if(this.isFolder) {
     this.open = !this.open
   }
  }
}

至此,一个基础的树形菜单功能已经实现,最终样式效果留给大家自行调整,此处提供完整代码供参考。


<template>
  <li>
    <div @click='toggle'>
      <i v-if='isFolder' class="fa " :class="[open?'fa-folder-open':'fa-folder']"></i>
      <!--isFolder判断是否存在子级改变图标-->
      <i v-if='!isFolder' class="fa fa-file-text"></i> {{model.data.menuName}}
    </div>
    <ul v-show="open" v-if='isFolder'>
      <items v-for='cel in model.childTreeNode' :model='cel'></items>
    </ul>
  </li>
</template>
<script type="text/javascript">
  export default {
    name: 'items',
    props: ['model'],
    components: {},
    data() {
      return {
        open: false,
        isFolder: true
      }
    },
    computed: {
      isFolder: function() {
        return this.model.childTreeNode && this.model.childTreeNode.length
      }
    },
    methods: {
      toggle: function() {
        if(this.isFolder) {
          this.open = !this.open
        }
      },
    }
  }
</script>

从树形菜单到树形表格

公司早期管理系统基于easyui构建,接手后使用Vue完整复刻了部分easyui的功能。下图展示了在树形菜单基础上进一步模仿实现的树形表格效果。

递归组件基础概念 

总结

以上就是本文的全部内容,希望这些内容能对各位的学习或工作有所帮助。如有任何疑问,欢迎留言交流。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章