来源 | https://wintc.top/article/13大概因为平时工作项目的原因,写了很多次树形组件,越写越觉得可以写得更简单并且更具有复用性、扩展性。树组件的应用场景很多,比如一篇文章的目录、一个公司部门组织情况、思维导图等,其实都可以用树形结构来描述。本文讲述一下Vue中树组件的简单实现。树组件在线体验地址:http://wintc.top/laboratory/#/tree。

一、树形数据结构

树形数据是指形如以下的数据结构:

[  {    id: '1',    title: '节点1'    children: [      {        id: '1-1',        title: '节点1-1'      },      {        id: '1-2',        title: '节点1-2'      }    ]  },  {    id: '2',    title: '节点2',    children: [      {        id: '2-1',        title: '节点2-1'      },      {        id: '2-2',        title: '节点2-2'      }    ]  },  {    id: '3',    title: '节点3'  }]

这并不是《数据结构与算法》里严格意义上的树定义,严格的树定义,第一层应该是一个根节点,而此处的第一层就包含了多个节点。不过这不重要,实用为上,这样的结构或许更加通用(试想,如果第一层是只包含一个节点的树,和标准定义的树又有什么本质区别呢)。树结构是递归的,它可能有很多级,我们在渲染树结构的时候也采用递归的方式来渲染。

二、Vue树组件实现的两个重要属性

1、组件的name属性

或许我们在平常开发的过程中都很少使用这个属性(至少我是如此),不过这个属性却有两个很重要的作用,摘自Vue官网:

  • 允许组件模板递归地调用自身。注意,组件在全局用 Vue.component() 注册时,全局 ID 自动作为组件的 name。

  • 指定 name 选项的另一个好处是便于调试。有名字的组件有更友好的警告信息。另外,当在有 vue-devtools,未命名组件将显示成 ,这很没有语义。通过提供 name 选项,可以获得更有语义信息的组件树。

这里我们因为要递归地渲染树形结构,即渲染树节点的时候使用当前组件作为子组件,所以会用到name属性。

2、插槽

Vue插槽借鉴于Web components,是在父组件自定义实现子组件部分dom的一个方法,这大大提高了子组件的复用性和扩展性。

下面是一个简单的插槽使用例子。

子组件:

  
子组件

父组件:

      
父组件通过插槽插入的内容——具名插槽

父组件通过默认插槽插入的内容——默认插槽渲染结果:父组件可以通过v-slot提供一些插槽来达到组件内容自定义的目的,只要子组件模板里预留了这些插槽的位置。插槽可以有名字作为唯一标识,如也可以不设置名字而使用默认值default;父组件中填充插槽使用v-slot:name填充对应的插槽,name表示填充的插槽名称,未指定名字的插槽填充时使用v-slot:default或v-slot,二者作用是相同的。关于Vue插槽,官网描述很清楚了,这里不再赘述。此处介绍几种插槽的特殊用法。

1)、作用域插槽

默认情况下,父组件模板里通过插槽插入的部分只能访问父组件上下文,如果你需要访问子组件的部分属性,可以通过作用域插槽:在子组件中给slot传递一些prop,然后在父组件插入内容时使用这些prop,示例如下。
子组件:

  
子组件

export default { data () { return { nodeData: { title: '节点1' } } }}父组件:

  
子组件传到插槽的nodeData的title:{{ someProp.nodeData.title }}

someProp是可以解构的,可以把从子组件传递给插槽的prop解构出来直接使用: v-slot:default="{ nodeData }"。

2)、插槽函数

从Vue2.6.0开始,所有的插槽(包括作用域插槽和普通插槽)都会作为一个函数,并通过vm.$scopeSlots暴露出来,比如上述父组件模板中给子组件插入了一个作用域插槽(名字为默认的default),在子组件实例的$scopeSlots就会暴露对应的函数:传递相应的参数(比如nodeData)调用这个函数,就可以得到插槽对应的虚拟DOM即VNode,在render函数中非常好使。只要你能访问到这个函数,就可以生成对应的虚拟DOM(并不是非得在当前组件),接下来在树组件叶子节点的渲染中,会用到这个用法。

三、树组件渲染的实现

1、树组件调用形式

作为一个可复用的树节点,渲染出来的树结构应该是可以自定义的,同时对于传入组件的prop尽可能简单。

这里设计的prop仅传入一个树形数据treeData,对于每一个节点,使用作用域插槽提供每一个节点的数据来调用者自定义渲染。所以组件调用形式很简单:

          
{{ nodeData.title }}

这里的调用仅仅把节点的文本渲染出来了,通常结合具体的场景,可能我们会有更多的功能需求,比如展开折叠,删除节点,添加节点等,给组件添加一个ref属性,我们可以方便地调用组件提供的函数。

2、树组件代码实现

通常递归实现树组件会分为两个部分:

  • 树节点渲染组件,该组件通过归调用自身渲染一个子树,一直递归到渲染完全部叶子节点。

  • 供外部调用的树形组件,提供一些外部调用的接口

下面直接给出树组件、节点组件的简单代码实现如下:树节点组件tree-node.vue:

  
:style="{ paddingLeft: indent }" v-if="nextShow"> v-for="(child, idx) of nodeData.children" :nodeData="child" :indent="indent" :key="idx">

export default { name: 'tree-node', props: { nodeData: { type: Object, required: true } }, components: { 'node-content': { render (h) { let slot = this.$parent.tree.$scopedSlots.default let { nodeData, parentData, level, nextShow } = this.$parent return (slot ? slot({ parentData, data: nodeData, level, nextShow }) : '

未定义插槽内容

') } } }, data () { return { tree: false, level: 0, parentData: null, childrenShow: true, indent: undefined } }, computed: { nextShow () { return this.nodeData.children && this.nodeData.children.length && this.childrenShow } }, created () { let parent = this.$parent if (parent.isTree) { this.level = 1 } else { this.level = parent.level + 1 this.parentData = parent.nodeData } while (parent && !parent.isTree) { parent = parent.$parent } this.tree = parent this.indent = this.tree.indent this.tree.registerNodeComponent(this.nodeData.id, this) }, beforeDestroy () { this.tree.removeNodeComponent(this.nodeData.id) }, methods: { showChildren (show) { this.childrenShow = show } }}树组件tree.vue:

  
v-for="(nodeData, idx) of treeData" :nodeData="nodeData" :key="idx">

import treeNode from './tree-node'export default { components: { treeNode }, props: { treeData: { type: Array, requied: true }, indent: { type: String, default: '20px' } }, data () { return { isTree: true, level: 0, componentMap: {} } }, methods: { registerNodeComponent (id, component) { this.componentMap[id] = component }, removeNodeComponent (id) { this.componentMap[id] = undefined }, showChildren (id, show) { this.componentMap[id] && this.componentMap[id].showChildren(show) } // 更多功能 }}.tree-container text-align left有几个点值得注意:

  • 树组件的componentMap保存了所有后代组件的引用。这样好处在于:在使用tree组件的时候,我们直接访问的只有树组件,想直接调用叶子节点的相关方法,可以通过树组件做转发。比如想让id为1的节点折叠起后代元素,可以调用this.$refs.tree.showChildren(1, true),在树组件的showChildren函数内,取出对应的节点组件,调用节点组件的方法。

  • 节点自身内容的渲染。节点组件的tree树形保存了树组件的引用,节点自身内容的渲染,使用了一个子组件node-content。而node-content的内容,来自于树组件的插槽,我们通过前面所描述函数形式访问到树组件的插槽,调用函数得到了虚拟DOM,作为组件node-content的内容。当然如果未提供插槽,node-content的内容会是一段提醒含义的html串,提醒使用者插入插槽(你也可以修改为一个默认的渲染,比如渲染出nodeData.title)。

  • 在提供的作用域插槽中,node-content组件向该插槽传递了parentData(上级节点数据), data(本级节点数据), level(层级)等一些可能常用的属性。

上述提供的树组件比较简单,仅仅提供了渲染树形结构、展开/折叠等功能,但是作为一个示例性的树形组件,它还是具有很强地扩展性以及复用性。因为使用Vue,我们用数据控制视图,所以你在使用的过程中想给组件增加比如节点多选、增删节点等操作,其实非常简单,你只用修改你的树形数据,并且在插槽上做相应的视图处理即可(比如增加选择框、添加下级/删除节点等菜单)。具体使用代码可以在github查看,或在线体验:http://wintc.top/laboratory/#/tree。本文完~

ant vue 树形菜单横向显示_快速实现一个简单可复用可扩展的Vue树组件相关推荐

  1. ant vue 树形菜单横向显示_丝滑般 Vue 拖拽排序树形表格组件Vue-DragTreeTable

    今天给小伙伴们分享一款纵享丝滑般体验的Vue拖拽树形表格DragTreeTable. vue-drag-tree-table 基于vue.js实现可拖拽排序的树形表格组件.支持拖拽排序.固定表头.拖拽 ...

  2. ant vue 树形菜单横向显示_ant design vue menu 导航菜单

    ant design vue menu 导航菜单 ant design vue menu 导航菜单是一个网站或者系统的重要功能,通过导航可以对网站或者系统的功能进行分门别类. 水平导航菜单 例子 首页 ...

  3. ant vue 树形菜单横向显示_Vue--组件Ant- 树形结构菜单

    defaultExpandAll :autoExpandParent="true" :treeData="treeData" @select="thi ...

  4. vue 圆形百分比进度条_快速构建一个圆形的进度条

    在一些特别生的网站上,用户需要一个可视化的是示,以表明网站资源仍然在加载.从Spinner到Skeleton屏幕有不同的方法来解决这类的用户体验效果. 如果我们使用的是开箱即用的解决方案,它为我们提供 ...

  5. django 引入同目录下py文件_快速开发一个简单的Django网站

    一.创建工程 1. 在cmd中输入:django-admin.py startproject projectname 2. 修改settings.py文件:在installedapp中增加需要创建的应 ...

  6. 智能机器人c语言编程,【图片】教你快速制作一个简单的人工智能机器人(懂编程的人进来看)【科幻吧】_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 教你快速制作一个简单的人工智能机器人(懂编程的人进来看) 本文我首发于"人工智能吧",叫做<机器人理解人类语言>和< ...

  7. 流媒体视频服务:快速搭建一个简单的流媒体视频服务(一)

    快速搭建一个简单的流媒体视频服务 前言 系统组成 RTMP协议简介 Red5 概述 Red5 服务器搭建 前言 最近自己在研究有关于流媒体播放的技术,网上资料甚少.出于开源精神以及在查阅资料得到各位大 ...

  8. 一个html写的app首页,如何快速开发一个简单好看的APP控制页面

    原标题:如何快速开发一个简单好看的APP控制页面 导读 机智云开源框架为了让开发者快速开发APP,已将用户登录,设备发现,设备配网等功能做成了各个标准模块,仅保留控制页面让开发者自行开发设计,节省了开 ...

  9. 使用SpringBoot一小时快速搭建一个简单后台管理(增删改查)(超详细教程)

    最近也是临近期末了,各种的期末大作业,后台管理也是很多地方需要用到的,为了方便大家能快速上手,快速搭建一个简单的后台管理,我花了两天时间整理了一下 我会从0开始介绍,从数据库的设计到前端页面的引入最后 ...

最新文章

  1. 盘点 Github 上的高仿 app 项目
  2. 【项目管理】RUP内容整理
  3. Android adb.exe程序启动不起来,如何处理
  4. 【白皮书分享】2020中国硬科技创新白皮书.pdf(附下载链接)
  5. Awesome Go
  6. linux的工程管理器是,Linux工程管理器——make
  7. Python unittest –单元测试示例
  8. Excel如何从身份证号码中提取性别
  9. 人工智能5秒免费抠图软件将改变设计行业???
  10. 百度指数对网站优化有什么作用
  11. 互联网产品运营——什么是产品运营?
  12. 轰动全球,一个月7级博客大V是如何炼成的!
  13. 推荐几款实现内网穿透的实用工具(转载)
  14. can和could的用法_情态动词can和could用法详解
  15. dataframe如何定义列名称
  16. Tushare学习文档(十 电影票房)
  17. 2017.10.27涩会题大乱斗部分题解
  18. VS2017安装打包工具;以及无法加载此项目,setup(不兼容),该应用程序未安装、MFC的使用
  19. 【陈工笔记】# WPS中如何公式居中,公式的编号靠右?#
  20. 如何在iPhone或iPad上使用Safari私人浏览

热门文章

  1. flutter创建一个demo
  2. @Cotroller和@RestCotroller
  3. 大班线描机器人_大班美术教案机器人
  4. abap 创建出口历程_SAP ABAP第一,两,三代出口型BADI实现 解释的概念
  5. c语言学习-输出9*9乘法口诀表
  6. 不显示样式 引用bootstrap_Bootstrap的引用样式
  7. OpenShift 4 - Fedora CoreOS (3) - 定制 CoreOS ISO
  8. 使用.NET Core进行Linux编程3:简介和第2章
  9. Visual Studio Code 1.45 发布
  10. PostgreSQL 荣获 2019 年 O'Reilly 终身成就奖