13.Vue技术栈开发实战-递归组件的使用
这是iview的menu的组件

http://v3.iviewui.com/components/menu


13.Vue技术栈开发实战-递归组件的使用


每一个菜单的item
13.Vue技术栈开发实战-递归组件的使用
实际的项目中,菜单往往是根据后台的数据返回回来的。往往是一个数组,通过这里,遍历然后循环生成的这个菜单,而不是这样写死的、
这个时候就用到了递归组件,

先来添加一个示例页,添加一个路由列表的配置项menu_page
13.Vue技术栈开发实战-递归组件的使用
在视图中创建这个menu-page
13.Vue技术栈开发实战-递归组件的使用

在components下创建menu文件夹,然后,分别创建3个vue文件。分别是
a-menu.vue
a-menu-item.vue
a-submenu.vue:收缩菜单的部分(子菜单)
13.Vue技术栈开发实战-递归组件的使用
aMenu最外层是div
13.Vue技术栈开发实战-递归组件的使用
创建index.js文件
13.Vue技术栈开发实战-递归组件的使用
把三个vue组件都引进来。然后再用export导出去
13.Vue技术栈开发实战-递归组件的使用
在menu-page引入这三个组件。并注册组件,这个地方用ES6的拆分操作符。它可以把一个对象都拆开,把里面的属性都拿出来,然后扁平化的塞到components对象里面。
13.Vue技术栈开发实战-递归组件的使用
然后就可以调用组件了。
13.Vue技术栈开发实战-递归组件的使用
a-menu里面给它加一个样式
13.Vue技术栈开发实战-递归组件的使用
这样html内就加进来了
13.Vue技术栈开发实战-递归组件的使用
ES6的三个点拆分操作符的话,这样在使用这个组件的时候就没有智能提示了。
13.Vue技术栈开发实战-递归组件的使用
我们用解构赋值的形式,把这三个组件注册在这个地方。
13.Vue技术栈开发实战-递归组件的使用
这样在写这个组件的时候,会有智能提示
13.Vue技术栈开发实战-递归组件的使用
菜单内容:里面用户可以定义任何东西,所以在item组件内这里我们用一个插槽slot
13.Vue技术栈开发实战-递归组件的使用
subMenu里面也是一个插槽
13.Vue技术栈开发实战-递归组件的使用
再加一个具名插槽,到时候用来显示标题的地方
13.Vue技术栈开发实战-递归组件的使用
在menu-page.vue内,在页面上先来用一下 
13.Vue技术栈开发实战-递归组件的使用
menu组件也要加上slot,a-menu.vue
13.Vue技术栈开发实战-递归组件的使用
给列表加一个样式
13.Vue技术栈开发实战-递归组件的使用

收缩的二级菜单

外层是一个aSubmenu里面也是menuItem
13.Vue技术栈开发实战-递归组件的使用
在subMenu里面我们之前定义了一个具名插槽,用来显示菜单的name值,
13.Vue技术栈开发实战-递归组件的使用


css属性加一个星,这样.a-menu下的所有样式都用list-style:none,这样菜单左边的小圆点就都没有了。
13.Vue技术栈开发实战-递归组件的使用
给item一个样式。给li加了一个背景色
13.Vue技术栈开发实战-递归组件的使用
二级菜单的标题也不要margin.
13.Vue技术栈开发实战-递归组件的使用
设置subMenu的样式。给最外层的div加个样式a-submenu.
把slot=title的也外层也放个div 给他一个class样式 a-submenu-title
13.Vue技术栈开发实战-递归组件的使用

 

<template>
  <ul class="a-submenu">
    <div class="a-submenu-title"><slot name="title"></slot></div>
    <slot></slot>
  </ul>
</template>

<script>
export default {
  name: 'ASubmenu'
}
</script>

<style lang="less">
.a-submenu{
  &-title{
    background: rgb(33, 35, 39);
  }
}
</style>

 



13.Vue技术栈开发实战-递归组件的使用


加上字体白色,二级菜单让他更明显显示
13.Vue技术栈开发实战-递归组件的使用
item也加上color为白色
13.Vue技术栈开发实战-递归组件的使用
把slot放在一个div里面,然后做一个收缩的效果。加载这个div上
13.Vue技术栈开发实战-递归组件的使用
如果需要控制它的显示隐藏,那么就需要v-show。肯定是通过一个变量来控制,默认是不显示的。
13.Vue技术栈开发实战-递归组件的使用
子菜单就没有显示了
13.Vue技术栈开发实战-递归组件的使用
通过点击title,切换它的显示与隐藏
13.Vue技术栈开发实战-递归组件的使用
点击显示子菜单
13.Vue技术栈开发实战-递归组件的使用
再次点击收回
13.Vue技术栈开发实战-递归组件的使用

加一个小图标的变化

让title这里知道当前是收缩还是展开的状态
13.Vue技术栈开发实战-递归组件的使用
隐藏的时候箭头朝下。如果showChild为false,那么就旋转180度

:style="{ transform: `rotateZ(${showChild ? 0 : 180 }deg)` }"

 


13.Vue技术栈开发实战-递归组件的使用

这样一个简单的菜单组件就封装好了。

嵌套

又嵌套一层
13.Vue技术栈开发实战-递归组件的使用

子菜单缩进效果↓↓↓↓

加一个缩进的效果,看出来层级的关系。修改下样式
13.Vue技术栈开发实战-递归组件的使用

递归

如何使用递归的形式把数据渲染出来。
13.Vue技术栈开发实战-递归组件的使用

data () {
    return {
      list: [
        {
          title: '1111'
        },
        {
          title: '2222'
        },
        {
          title: '3333',
          children: [
            {
              title: '3333-1'
            },
            {
              title: '3333-2',
              children: [
                {
                  title: '33333-2-1'
                },
                {
                  title: '33333-2-2'
                }
              ]
            }
          ]
        }
      ]
    }
  }

 



接下来要渲染数据list。先把这里原来写的注释掉。
13.Vue技术栈开发实战-递归组件的使用
先把子级别的菜单注释掉。渲染第一个级别,
13.Vue技术栈开发实战-递归组件的使用
一级菜单可以直接写a-menu-item 上v-for循环就可以。
13.Vue技术栈开发实战-递归组件的使用
但是因为我们待会还有二级的菜单,所以这里我们用template组件来渲染。
13.Vue技术栈开发实战-递归组件的使用

渲染子节点

封装一个递归组件,re-submenu.vue
13.Vue技术栈开发实战-递归组件的使用
引入subMenu和menuItem并注册
13.Vue技术栈开发实战-递归组件的使用
外层是a-submenu,里面是a-menu-item
13.Vue技术栈开发实战-递归组件的使用
如果有子菜单还是要嵌套一层a-submenu里面是a-menu-item
13.Vue技术栈开发实战-递归组件的使用
子节点调用当前这个组件。自己调用自己
13.Vue技术栈开发实战-递归组件的使用
自己调用自己,如果不设置条件的话,就会一直循环下去。这样就是个死循环。

所以。循环我们放在template上
13.Vue技术栈开发实战-递归组件的使用
每一个元素都有一个key
13.Vue技术栈开发实战-递归组件的使用
如果item没有children
13.Vue技术栈开发实战-递归组件的使用
显示的内容就是item.title
13.Vue技术栈开发实战-递归组件的使用
如果有children,既要显示它的title还要在下面遍历这个children
13.Vue技术栈开发实战-递归组件的使用

首先是显示title。
13.Vue技术栈开发实战-递归组件的使用
那么我们怎么把这个title传进去呢?首先在这里引入这ReSubmenu这个组件,
13.Vue技术栈开发实战-递归组件的使用
这里定义一个parent的属性,传入的就是上面的item对象。
13.Vue技术栈开发实战-递归组件的使用

13.Vue技术栈开发实战-递归组件的使用


title传进来之后,递归组件就知道用谁了。接收传递过来的属性parent
13.Vue技术栈开发实战-递归组件的使用
直接返回一个值的情况可以这么写
13.Vue技术栈开发实战-递归组件的使用
那么这里显示的parent的title
13.Vue技术栈开发实战-递归组件的使用
页面上出错
13.Vue技术栈开发实战-递归组件的使用
应该是key重复了。我们这里是0。这个地方就叫做menu_item_0
13.Vue技术栈开发实战-递归组件的使用
在递归组件这里还是 menu_item_0 所以肯定是有问题的。
13.Vue技术栈开发实战-递归组件的使用
所以我们应该同时把索引号也传进去,做一个拼接
13.Vue技术栈开发实战-递归组件的使用
递归组件内接收index。这里先改成i不用index了。因为我们要定义一个index的属性
13.Vue技术栈开发实战-递归组件的使用
这里是传入的index属性,然后再拼接上i
13.Vue技术栈开发实战-递归组件的使用
下面也是这样
13.Vue技术栈开发实战-递归组件的使用
页面还是报错
13.Vue技术栈开发实战-递归组件的使用
这里我们加上判断,如果有children才显示下面的递归对象。
13.Vue技术栈开发实战-递归组件的使用
递归组件内,这里也要写一个v-else
13.Vue技术栈开发实战-递归组件的使用

这里改成parent.children就没错了。
13.Vue技术栈开发实战-递归组件的使用
菜单就根据数组渲染出来了。
13.Vue技术栈开发实战-递归组件的使用
还可以有更深的层级。可以无线级的往下写。
13.Vue技术栈开发实战-递归组件的使用

这就是的递归组件的使用。

一定要注意一定要有个能够终止递归组件的条件。这里是用v-if 和v-else。
第二是递归组件一定要有一个name值
13.Vue技术栈开发实战-递归组件的使用


后面在讲能收缩的菜单的时候,还会用到递归组件

递归组件代码

 

<template>
  <a-submenu>
    <div slot="title">{{ parent.title }}</div>
    <template v-for="(item, i) in parent.children">
      <a-menu-item v-if="!item.children" :key="`menu_item_${index}_${i}`">{{ item.title }}</a-menu-item>
      <re-submenu v-else :key="`menu_item_${index}_${i}`" :parent="item"></re-submenu>
    </template>
  </a-submenu>
</template>

<script>
import menuComponent from '_c/menu'
const { AMenuItem, ASubmenu } = menuComponent
export default {
  name: 'ReSubmenu',
  components: {
    AMenuItem,
    ASubmenu
  },
  props: {
    parent: {
      type: Object,
      default: () => {}
    },
    index: Number
  }
}
</script>

<style>

</style>
re-submenu.vue

相关文章: