先来看最终成果:
操作逻辑为:
点击 ... 弹出 context-menu;
点击非 context-menu 区域,隐藏 context-menu;
点击 context-menu 中的任何一个选项,隐藏 context-menu;
思考
项目是基于 vux 做的,本想着偷懒直接在 vux 库翻组件用,但看了一圈下来,居然这么通用的组件在 vuex 中没有!接着又去翻开源的解决方案,看了几个库还算 ok,但此时前端小哥来了,说实现这个菜单不需要用到这么重的东西,直接写就行了。
当时我的脑海中在思考了把 context-menu 封装成一个 component ,通过数据配置的方式动态拓展菜单选项。但没想到前端小哥直接给我干了回来,没必要进行封装,这个组件对页面依赖性太强,就算封装完了下次也不一定能直接用,PM 的思路又这么清奇。
所以,最后的做法就直接硬上了。
实现
调整操作逻辑
该页面是一个通俗意义上的列表展示页,使用了 vux 的 swipeout 表单组件,给用户提供了侧滑操作,需要把原先写好的侧滑功能删除。
调整 UI
在调整 UI 的过程中我感到了 CSS 满满的恶意,当然说是这么说,但实际上还是因为太久没有用而导致的不够熟悉。非常费劲的终于调整了好了新 UI,此时已经过去了整整一天了,非常怀念 autoLayout 。
context-mune
在正式开始写之前,上文已经说了我一直在翻开源库,主要是不懂得如何下手去写。距离上一次写 vue 已经过去快两个月了,而且也没搞清楚如何写一个组件,所以中间有一段时间浪费在了这上。最后的解决思路让我感到意外:
<div> <ul v-show="item.showOption"> <li>更换分类</li> <li>向上移动</li> <li>移至顶部</li> <li>取消收藏</li> </ul> </div>
没想到使用无序列表就可以完成了~在 iOS 中,我会在 UITableView 和 UIStackView 中纠结。当然只有这样是不行的,当又调整了 UI 后,发现 ... 和 context-menu “融合”在了一起,没有设计图中的“悬浮”效果,最后的解决方法是:
.more-wrapper { /* ... */ position: absolute; .more-menu-wrapper { position: relative; /* ... */ } }
当继续调整 CSS 时又发现 context-menu 的会被其父组件挡住, context-menu 的显示范围会限制于其父组件的显示高度,最后得知是 overflow 这个属性在最底层的父组件中设置了 overflow: hidden; ,删除掉,使其为默认的 visible 即可显示为 context-menu 高度溢出的效果。
事件绑定
UI 都调整完后开始绑定事件。因为只是改造 UI,并没有涉及到多少的新逻辑,所以很快的就写出了以下代码:
<ul v-show="item.showOption"> <li @click="moveItem(item)">更换分类</li> <li @click="moveUp(item)">向上移动</li> <li @click="setTop(item)">移至顶部</li> <li @click="deleteItem(item)">取消收藏</li> </ul>
context-menu 的显示依赖 v-show ,当页面首次拉取到网络数据时, data 中对每个 listData 的 item 新增了 context-menu 显示隐藏的初始化标志位 item.showOption = false ,且在这四个入口方法中都控制了 item.showOption 的改变:
//... moveUp(item) { item.showOption = false; // ... } //...
刷新页面,很愉快的看到了 context-menu 的显示,但在点击菜单选项时没有任何反应!一开始以为是标志位的问题,但看来看去没有任何问题。
本来想去找前端小哥看一眼,但一直不在工位上,最后问了下同组的前端实习生,他认为是 item.showOption 字段在数据更新时没有加上,导致后续直接读取时不存在。
但我其实一直纳闷如果 item.showOption 字段数据不存在的话,那第一次的页面渲染实际上是有错误的。我们两个人看了一会也没发现具体是哪有问题,最后只能四处寻找前端小哥,没想到他已经被封闭起来做商业化了......
前端小哥在文件中加上了 debugger 进行调试,发现进入到 moveUp 等一类事件时虽然 item.showOption 被修改成功了,一旦出去事件周期外,又被改回去了。
最后发现,问题出在被 冒泡 到了父组件中,调用了 ... 所绑定的 onMore 事件中,而在 onMore 事件中 item.showOption = true ,所以实际上是执行了 context-menu 和 ... 的两者所绑定的事件。解决的方法是:
<ul v-show="item.showOption"> <li @click.stop="moveItem(item)">更换分类</li> <li @click.stop="moveUp(item)">向上移动</li> <li @click.stop="setTop(item)">移至顶部</li> <li @click.stop="deleteItem(item)">取消收藏</li> </ul>