原标题:Vue 递归组件构建一个树形菜单

Vue.js 中的递归组件是一个可以调用自己的组件例如:

Vue.component('recursive-component', {

template: ``

});

递归组件一般用于博客上显示评论,树形菜单或者嵌套菜单。

一、初始化

我们直接使用 vue 提供的脚手架 vue-cli 来初始化我们的工程:

# 搭建项目

vue init webpack-simple tree-menu

# 进入项目

cd tree-menu

# 依赖安装

npm install

# 运行项目

npm run dev

现在我们的环境已经准备好了,在初始化的项目中,有一些不需要的代码我们可以自己动手删除。

二、数据结构

在本教程中,我们将使用一个树结构的数据来作为我们的每个菜单项,其中每个节点都是一个对象:

label 属性,作为菜单的列表,如果该菜单下还有子菜单,就需要一个 nodes 属性,这是一个或多个节点的数组。

这里需要注意的是像所有的树结构一样,必须有一个根节点,然后从这个根节点进行无限嵌套。

let tree = {

label: 'root',

nodes: [

{

label: 'item1',

nodes: [

{

label: 'item1.1'

},

{

label: 'item1.2',

nodes: [

{

label: 'item1.2.1'

}

]

}

]

},

{

label: 'item2'

}

]

}

三、递归组件

将 src 下的 app.vue 修改为 TreeMenu.vue ,该组件将作为我们的树形的递归组件,用来显示当前节点和自己的子节点。

{{ label }}

v-for="node in nodes"

:nodes="node.nodes"

:label="node.label"

>

<>

export default {

props: [ 'label', 'nodes' ],

name: 'tree-menu'

}

>

如果您正在使用递归组件,则必须使用全局注册 Vue.component,或者给它一个 name 属性。否则,组件的任何子节点将无法解析进一步的调用,并且会得到未定义的组件错误。

和任何递归函数一样,我们需要一个条件来结束递归,否则渲染将无限期地继续下去,最终会导致堆栈溢出。

在我们的树形菜单中,当我们到达一个没有子节点的节点时,我们想要停止递归。你可以用 v-for ,如果 nodes 数组未定义,tree-menu 则不会继续调用组件。

...

四、主模块

在主模块 main.js 中声明一个树形结构的数据,并将该数据作为 data 属性的值,并引入 TreeMenu 组件 。

/* ./src/main.js */

import TreeMenu from './TreeMenu.vue'

let tree = {

...

}

new Vue({

el: '#app',

data: {

tree

},

components: {

TreeMenu

}

})

由于我们的数据结构只有一个单一的根节点。为了开始递归,我们将 TreeMenu 组件作为根节点的子节点,修改根目录下的 index.html 文件:

五、缩进

为了让用户可以直观地识别子组件,就有必要对每一层的子节点进行缩进。为了实现该效果,我们通过添加一个 depth 来实现。使用这个值来动态设置 css 中的 transform 属性,从而实现缩进效果。

{{ label }}

v-for="node in nodes"

:nodes="node.nodes"

:label="node.label"

:depth="depth + 1"

>

<>

export default {

props: [ 'label', 'nodes', 'depth' ],

name: 'tree-menu',

computed: {

indent() {

return { transform: `translate(${this.depth * 50}px)` }

}

}

}

>

同时在 index.html 上将 depth 设置为从零,也就是初始的时候是没有缩进的。这样每次将该值传递给任何子节点时,该值都会增加。

:label="tree.label"

:nodes="tree.nodes"

:depth="0"

>

注意:depth 的值要确保它是一个 Java 数字而不是一个字符串。

六、收缩

在初始的时候,应该只显示根节点,其他节点全部隐藏,然后通过鼠标点击的时候,能够展开各个节点。

为此,我们将添加一个本地状态 showChildren 。如果该值为 false,则不显示子节点,如果为 true 则显示子节点。而这个值应该通过鼠标点击节点来进行切换,所以我们需要一个点击事件:

{{ label }}

v-if="showChildren"

v-for="node in nodes"

:nodes="node.nodes"

:label="node.label"

:depth="depth + 1"

>

<>

export default {

props: [ 'label', 'nodes', 'depth' ],

data() {

return { showChildren: false }

},

name: 'tree-menu',

computed: {

indent() {

return { transform: `translate(${this.depth * 50}px)` }

}

},

methods: {

toggleChildren() {

this.showChildren = !this.showChildren;

}

}

}

>

七、样式

经过以上步骤就已经完成了一个基本的树形菜单。为了使 UI 效果更佳,我们可以添加一个加号和减号图标,使用户界面更加明显。以下是全部的代码:

:label="tree.label"

:nodes="tree.nodes"

:depth="0"

>

/* ./src/main.js */

import Vue from 'vue'

import TreeMenu from './TreeMenu.vue'

import './assets/app.css'

//定义树形菜单数据

let tree = {

label: 'root',

nodes: [

{

label: 'item1',

nodes: [

{

label: 'item1.1'

},

{

label: 'item1.2',

nodes: [

{

label: 'item1.2.1'

}

]

}

]

},

{

label: 'item2'

}

]

}

new Vue({

el: '#app',

// render: h => h(App)

data: {

tree

},

components: {

TreeMenu

}

})

{{ label }}

v-if="showChildren"

v-for="node in nodes"

:nodes="node.nodes"

:label="node.label"

:depth="depth + 1"

>

<>

export default {

props: [ 'label', 'nodes', 'depth' ],

name: 'tree-menu',

data() {

return { showChildren: false }

},

computed: {

iconClasses: function iconClasses() {

return {

'plus': !this.showChildren,

'minus': this.showChildren

};

},

labelClasses: function labelClasses() {

return { 'has-children': this.nodes };

},

indent() {

return { transform: `translate(${this.depth * 50}px)` }

}

},

methods: {

toggleChildren() {

this.showChildren = !this.showChildren;

}

}

}

>

./src/assets/app.css

body {

font-family: sans-serif;

font-size: 18px;

font-weight: 300;

line-height: 1em;

}

.container {

width: 300px;

margin: 0 auto;

}

.tree-menu .label-wrapper {

padding-bottom: 10px;

margin-bottom: 10px;

border-bottom: 1px solid #ccc;

}

.tree-menu .label-wrapper .has-children {

cursor: pointer;

}

.plus:before {

content:'+';

}

.minus:before {

content:'-';

}

本文章由源码时代H5学科讲师原创!

转载须注明出处(http://www.itsource.cn)!感谢大家的配合!返回搜狐,查看更多

责任编辑:

vue 递归组件多级_Vue 递归组件构建一个树形菜单相关推荐

  1. vue 递归组件多级_Vue递归组件实现树形结构菜单

    Tree 组件是递归类组件的典型代表,它常用于文件夹.组织架构.生物分类.国家地区等等,世间万物的大多数结构都是树形结构.使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能. 如图所示 ...

  2. vue 组件数据共享_Vue共享组件

    vue 组件数据共享 As a company, we sell experiences on many different sales channels, gotui.com, musement.c ...

  3. vue 父链和子组件索引_vue子组件和父组件双向绑定的几种方案

    v-model案例 模仿v-model实现案例 我是一串要和内部名字联动的一串文字(父组件) 父组件改变值带动(父组件)点一下试试 .sync方案实现案例 这是父组件的东西.利用这个框改变值,看看有没 ...

  4. vue 父组件调子组件方法_vue父组件调用子组件有哪些方法

    这次给大家带来vue父组件调用子组件有哪些方法,vue父组件调用子组件的注意事项有哪些,下面就是实战案例,一起来看一下. 情景: 父组件中引入上传附件的子组件:点击组件可以分别上传对应要求的图片,子组 ...

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

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

  6. vue 获取当前路由_VUE 在组件中 获取 路由信息

    一.核心代码 1.获取参数 this.$route.query.id this.$route.query 2.页面跳转 登录 3.方法跳转 this.$router.push({ path: '/lo ...

  7. 子组件调用父组件方法_vue父子组件通信以及非父子组件通信的方法

    组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系,父子关系.兄弟关系和隔代关系,简化点可以分为父子关系和 ...

  8. python三级联动菜单_VUE+element三级联动或树形菜单获取最后一项,并加入到表格中...

    如下图,要实现的功能如下,勾选三级联动的材料,勾选最后一级的材料,把勾选的材料信息动态添加到下面表格中 1 data数据 return { options:[], // 三级联动 数据 options ...

  9. Vue封装树形菜单组件

    csdn终于更新完成了哈,ok,步入正题 像这种树形结构的核心思想就是:递归思想,知道使用递归,其实这个例子函数的封装也就很简单喽 实现步骤: 设置的props:                    ...

最新文章

  1. 软件性能测试瓶颈定位,软件性能问题正确定位思路
  2. java while do_java中while和do-while的总结
  3. vue自动提交表单_(尚012)Vue表单数据的自动手集(表单数据提交,需要收集表单数据)...
  4. 电动车爬坡时究竟应该用最快档还是用最慢档?
  5. 数据分析 | 这个新职业年薪高达49w,作为普通打工人的你眼馋了吗?
  6. HDOJ1005(找循环节点)
  7. 拉格朗日插值编程实现
  8. zookeeper集群节点热扩容和迁移详解
  9. 20130331java语言基础学习笔记-语句_breakcontinue
  10. 单片机毕业设计 超声波雷达可视化系统
  11. 【研发管理】质量管理之约瑟夫·M.朱兰
  12. linux系统设置中文
  13. 四年的自学,通过这些学习工具拿到了大厂offer,分享给大家
  14. 修路【NOIP2016提高组模拟】
  15. 解决支付订单,重复提交问题!
  16. appiume连接逍遥模拟器
  17. 金九银十,测试思维面试题最新整理
  18. Thread.currentThread()方法 Runnable
  19. 行通信比并行通信的速度更高
  20. java代理一(静态代理)

热门文章

  1. Android 自定义ViewGroup
  2. 搞懂 mismatch dep signature
  3. Android手机中第三方签名应用程序无法获得的permission
  4. 《『若水新闻』客户端开发教程》——12.代码编写(4)
  5. 关闭selinux服务
  6. pipreqs 组件
  7. 关于权限的数据库设计
  8. Docker常见问题总结(持续更新)
  9. Pascal 语言中的关键字及保留字
  10. iOS开发之地图与定位