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事件
只希望触发一次事件。如果当前不是第一级 输出。
这样就只处罚一次事件了
这里我们需要在这里抛出一个事件
这样就没有问题了 点击事件
以上就算是封装完成了。
代码
结束