16.Vue技术栈开发实战-可收缩多级菜单的实现

实现可收缩的侧边栏菜单。

效果展示

点击收缩的效果。如果只有一级菜单



二级菜单

多级菜单的情况

展开的效果

多级菜单

开始

我们之前封装的,我们的菜单要放在layout里

我们最后封装的菜单组件,是要在sider里面

sider-menu组件

分别加sider-menu-submenu和side-menu-dropdown


另外两个按钮 值在sideMenu里面用,所以这里就不导出去了。光导出sideMenu

展开的时候用的iview的menu组件。
收起来用的是dropDown组件

它其实是一个个的按钮图标

所以在我们的组件最外层肯定是有一个控制,默认是menu。dropDown放在下面的div里面。

顶部需要一个logo



所以顶部的log位置是允许自定义内容的,所以我们想到可以用slot插槽。在最上面用slot插槽。如果 还有其他的插槽 可以在底部也放一个slot

展开是有状态的,我们在layout组件内是有这么个状态的。为true就是收缩。所以这个组件要把状态传进去。

所以我们在layout里面

调用组件,把属性:collapsed加进去。

组件内定义collapsed属性。默认是展开的。

menu展开的情况

每一条menu-item就是一个菜单

通过一个数组来渲染菜单。所以这个地方应该是用一个v-for去循环生成。我们如果在这里用v-for去循环的呢,只能循环出来一级

如果我们的层级是很多级呢?而且层级的多少是不确定的呢

我们之前讲过一个递归组件的形式,所以这里地方我们就要用到递归组件。

在定义数据。用到iview里面的icon图标



定义属性叫做list。把这个list传递进去。

组件内定义属性 list

默认如果是一个空数组,要在回调函数里面给它return 一个空的数组

上面是简写的形式,补全的写法就是这种

如果要返回一个空对象呢,不能直接写空对象,要用括号括起来。

最终我们默认是这样的

要递归组件,外层用template

给没一个menu都加上一个name的属性

用menu的name值来做key。这里判断item.children

这个可以也要给组件menu-item

menu-item上还需要一个nam的属性

Submenu也需要name属性。



最外层的div 宽度 要和父容器相等。

所以设置div的宽度是100%

菜单的宽度,来看下文档,它可以设置一个width值


主题设置为dark,这样北京颜色都是黑色了

有子菜单的情况

因为我们的层级是未知的,所以这里需要用到递归组件。
哪个部分是一直在循环下去的,就把谁拆出来 组装成一个组件。这里很显然,subMenu里面裹着menuItem。然后里面又有一个subMenu裹着menuItem。所以我们应该把subMenu拆出来,拆成递归组件。

我们在side-menu-submenu里面封装。

起个名字叫做ReSubMenu

所以我们side-menu-submenu.vue改名叫做submenu

side-menu-dropdown.vue也改名re-dropdown.vue

应该把这整个对象传给递归组件。

ReSubMenu引进来。

这个地方就改成re-submenu

组件定义了很多的条件和属性的话,可以分行显示、这样比较清晰一些。

传入当前的item对象当做数据。对组组件内部来说,它就是当前的父级。

递归组件内,定义parent属性。

首先需要一个东西来作为插槽。显示当前这个submenu的title

直接复制过来



这样第一层就显示出来,

接下来里面裹着的是menuItem

menuItem应该使用v-for渲染children里面的数组了

所以这里是个v-for

在side-menu里面,在遍历的时候,是v-for循环一个template。在里面去判断当前item有没有children

这块逻辑,在递归组件里面是复用的

所以这里复制过来,逻辑应该是一样的

ist改成parent.children

递归组件,一定要给他一个name值。递归组件通过name值去调用他自身。


 
subMenu需要一个name的属性。




为了好看,把标题的name改的短一点





side组件可以设置宽度。这里设置为300试一下

递归组件内,只定义了title没有定义图标







这里把所有的东西都包在了title里面

单独的移除来

这样 样式就对了

再次强调递归组件的使用要领

组件里面,每一块都是不断的在重复下去的。那你就应该把每一部分拆成一个组件。当递归组件使用。

菜单收缩的功能

这里这么窄,用menuItem肯定是不行的。

先把上面的递归组件先注释掉。这里还是用template循环list

没有children的情况下的效果图

完成用Tooltip。里面裹着我们的a标签。

for循环没个元素都要有key

现在a标签都显示在一排了。

所以需要给他一个样式。width是1000%,同时设置它为块级别的元素。

这个地方受了ToolTip的影响

为了不受tooltip的影响。加transfer属性
a标签的外面裹了,ivu-tooltip


把ivu-tooltip也设置成一个块级选择器。

这样就换行了。

图标显示的有点小。size设置为20

图标呢,希望是白色



tooltip的方向子设置在右边


 
设置图标居中。这样图标就居中了。

上下的padding,让图标之间有间隔

默认的状态设置为收缩的状态

子对象-dropdown递归组件封装

定义属性parent,返回默认还是一个空对象。

dropdown需要定义一个元素,是作为你鼠标触发显示的。把side-menu的a标签复制过去。



把ReDropmdown引进来,然后使用这个组件。

同样它也需要一个key,因为是v-for循环里面的

传入parent属性

报错

这里加上v-if和v-else的判断



DropdownMenu的 slot是list。里面用Template循环。



加上name属性。

这里的图标没有居中

这里现在有菜单了

把title显示出来



显示在右边,右边开始的方向。

接下来显示父界别的title,用span标签去显示。

发现第一级也显示了title。我们希望的效果是菜单的第一级是不显示title的

在里面显示title。而且这里看不到有问题,这是因为之前设置的文字颜色为白色导致的。

这里把字体颜色白色去掉。不应该用css样式去写了 

第一级的icon颜色设置为白色。

icon-color设置为白色


多级里面的颜色为

递归组件内默认值就为灰色

传入color为IconColor

里面是对的,但是文字颜色不太对。文字颜色应该和图标的颜色是一样的

因为我们是写在a那标签里面的,这里换成span标签。那么就不用再单独定义颜色了。

这里也换成span标签,并且把class的类名改成drop-menu-span

css里面也修改为drop-menu-span

递归组件内也改

我们应该是让第一级不显示title,让里面显示title

也是和color一样,我们传入一个属性

定义title的属性。默认是true,显示的

第一级菜单我们不显示

然后控制Title的显示

这里也显示图标

这里类型就是item.icon

第一级的图标还是白色

color属性改成这样

具有字节别的菜单 居中的问题,所以居中的样式我们要改变一下。如果showTitle为true的话,说不它不是第一级

不是第一级就偏左,否则的话就是居中

现在是偏左的,但是的话 我们应该给他一个padding-left

因为样式比较复杂,所以我们直接写在计算属性里

return一个对象。



然后是一级菜单居中的效果。这里不能设置它的宽度是100%了。因为给这个ivu-dropdown类型设置为100%后,那么后面你这些子菜单是根据父元素的ivu-dropdown的类名 的宽度来定义的。 那你后面的宽度都这么宽了。

所以这里我们应该使用一个技巧。
最外层的div给它一个类名



给他设置为块级别元素,然后marin:0 auto;居中



这样菜单就好看多了

控制收缩和展开的状态

把注释的代码都放开



展开

收缩

v-if和v-show的对比

都能实现对元素显示和隐藏的控制
如果设置v-if为false。组件直接就不渲染了。
v-show为false,只是设置css为display为none,里面的内容实际都是渲染出来了。
所以当我们有时候会频繁的切换show或者hide的时候,我们应该使用v-show.这样就能减少我们性能的开销。

所以这里我们要用v-show

添加事件

我们要知道,当前点击的是哪一项。

把选中的name值打印一下




收缩的状态下点击事件

span绑定click事件,传入item.name



dropdown绑定onclick事件





点击这里,onclick事件触发了两次

因为我们的组件嵌套了多次。触发了多个onclick事件

只希望触发一次事件。如果当前不是第一级 输出。


这样就只处罚一次事件了

这里我们需要在这里抛出一个事件


这样就没有问题了 点击事件


以上就算是封装完成了。
 

代码




 

结束

 

posted @ 2020-07-05 19:22  高山-景行  阅读(1094)  评论(0编辑  收藏  举报