# WXDropDownMenu **Repository Path**: dotton/WXDropDownMenu ## Basic Information - **Project Name**: WXDropDownMenu - **Description**: 小程序下拉菜单,可用于筛选 - **Primary Language**: 微信 - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 40 - **Forks**: 16 - **Created**: 2016-10-07 - **Last Updated**: 2023-12-17 ## Categories & Tags **Categories**: weixin-lapp **Tags**: None ## README 先来看下效果图: ![效果图](https://static.oschina.net/uploads/img/201610/08171205_p1hX.gif "效果图") 思路与步骤: 布局方面,整体使用dl来写,二级包在dd中,用ul li来写;交互方面,点击某一级菜单,关闭兄弟子菜单,点击某子菜单关闭所有菜单。 1.使用dt做出第一级菜单 2.使用dd嵌套第二级菜单,初始隐藏、position为absolute,使用z-index浮出页面层 ``` /*总菜单容器*/ .menu { display: block; height: 38px; } /*一级菜单*/ .menu dt { font-size: 15px; float: left; /*hack*/ width: 33%; height: 38px; border-right: 1px solid #d2d2d2; border-bottom: 1px solid #d2d2d2; text-align: center; background-color: #f4f4f4; color: #5a5a5a; line-height: 38px; } /*二级菜单外部容器样式*/ .menu dd{ position: absolute; width: 100%; /*hack*/ top:39px; left:0; z-index:999; } /*二级菜单普通样式*/ .menu li{ font-size: 14px; line-height: 34px; color: #575757; height: 34px; display: block; padding-left: 8px; background-color: #fff; border-bottom: 1px solid #dbdbdb; } ``` 查看效果,接下来实现点击事件。 如图 ![静态菜单](https://static.oschina.net/uploads/img/201610/08171124_XEjU.png "静态菜单") 3.dt绑定点击事件tapMainMenu,flag控制显隐toggle,提供2个class,hidden与show,来控制显隐。注:dt也是可以bindTap的,不单是view。 ``` /* 显示与隐藏 */ .show { display: block; } .hidden { display: none; } ``` 4.关闭所有一级菜单,每个一级菜单都有一个index标识,由tapMainMenu事件传递过去,与数组subMenuDisplay一一对应,当前元素subMenuDisplay[index]视原来状态决定是显示或隐藏。 核心代码: ``` ``` ``` // 使用function初始化array,相比var initSubMenuDisplay = [] 既避免的引用复制的,同时方式更灵活,将来可以是多种方式实现,个数也不定的 function initSubMenuDisplay() { return ['hidden', 'hidden', 'hidden']; } Page({ data:{ subMenuDisplay:initSubMenuDisplay() }, tapMainMenu: function(e) { // 获取当前显示的一级菜单标识 var index = parseInt(e.currentTarget.dataset.index); // 生成数组,全为hidden的,只对当前的进行显示 var newSubMenuDisplay = initSubMenuDisplay(); // 如果目前是显示则隐藏,反之亦反之。同时要隐藏其他的菜单 if(this.data.subMenuDisplay[index] == 'hidden') { newSubMenuDisplay[index] = 'show'; } else { newSubMenuDisplay[index] = 'hidden'; } // 设置为新的数组 this.setData({ subMenuDisplay: newSubMenuDisplay }); } }); ``` 5.选中二级菜单当前项,但给个系统icon及改变背景色,文本加粗,同样改变一级菜单标题,demo中给出一个弹窗 声明tapSubMenu方法,监听二级点击事件 ``` tapSubMenu: function(e) { // 获取当前显示的一级菜单标识 var index = parseInt(e.currentTarget.dataset.index); console.log(index); // 隐藏所有一级菜单 this.setData({ subMenuDisplay: initSubMenuDisplay() }); } ``` 加highlight效果 ``` /*二级菜单高亮样式*/ .menu li.highlight{ background-color: #f4f4f4; } ``` 与一级菜单不同,使用二维数组的方式实现点击高亮,这样才能定位到是某一级的某二级菜单,再决定显示隐藏。 布局文件改成: ```
``` 效果如图 ![子菜单高亮](https://static.oschina.net/uploads/img/201610/08171231_Khl7.png "子菜单高亮") 相应的js代码要写成: ``` //声明初始化高亮状态数组 function initSubMenuHighLight() { return [ ['','','','',''], ['',''], ['','',''] ]; } ``` 点击事件 ``` tapSubMenu: function(e) { // 隐藏所有一级菜单 this.setData({ subMenuDisplay: initSubMenuDisplay() }); // 处理二级菜单,首先获取当前显示的二级菜单标识 var indexArray = e.currentTarget.dataset.index.split('-'); console.log("indexArray : " + indexArray); var newSubMenuHighLight = initSubMenuHighLight(); // 与一级菜单不同,这里不需要判断当前状态,只需要点击就给class赋予highlight即可 newSubMenuHighLight[indexArray[0]][indexArray[1]] = 'highlight'; console.log(newSubMenuHighLight); // 设置为新的数组 this.setData({ subMenuHighLight: newSubMenuHighLight }); } ``` 这样就实现了高亮与取消高亮。但还没完,与一级菜单不同,这里与兄弟子菜单是非互斥的,也就是说点击了本菜单,是不能一刀切掉兄弟菜单的高亮状态的。于是我们改进js代码。 声明方式,改用变量形式,方便存储。 ``` //定义初始化数据,用于运行时保存 var initSubMenuHighLight = [ ['','','','',''], ['',''], ['','',''] ]; ``` 点击事件 ``` tapSubMenu: function(e) { // 隐藏所有一级菜单 this.setData({ subMenuDisplay: initSubMenuDisplay() }); // 处理二级菜单,首先获取当前显示的二级菜单标识 var indexArray = e.currentTarget.dataset.index.split('-'); // 初始化状态 // var newSubMenuHighLight = initSubMenuHighLight; for (var i = 0; i < initSubMenuHighLight.length; i++) { // 如果点中的是一级菜单,则先清空状态,即非高亮模式,然后再高亮点中的二级菜单;如果不是当前菜单,而不理会。经过这样处理就能保留其他菜单的高亮状态 if (indexArray[0] == i) { for (var j = 0; j < initSubMenuHighLight[i].length; j++) { // 实现清空 initSubMenuHighLight[i][j] = ''; } // 将当前菜单的二级菜单设置回去 } } // 与一级菜单不同,这里不需要判断当前状态,只需要点击就给class赋予highlight即可 initSubMenuHighLight[indexArray[0]][indexArray[1]] = 'highlight'; // 设置为新的数组 this.setData({ subMenuHighLight: initSubMenuHighLight }); } ``` 有待完善功能点: 1.显示与隐藏带动画下拉 2.抽象化,使用回调函数,将1监听每个二级菜单的点击 3.数据源与显示应当是分离的,一级与二级菜单的key value应该是独立在外,系统只认index,然后对相应点击作处理,跳转页面,筛选结果等 [2016-10-18] 官方文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-animation.html ![图](https://static.oschina.net/uploads/img/201610/19094056_owgS.gif "效果图") 改为动画版,需要要满足平移动画与背景遮罩。思路如下: 1.二级菜单初始隐藏且位置位于手机屏幕之外 2.当点击一级菜单时,二级菜单平移向下,直到二级菜单上边缘与一级菜单下边缘平齐。使用linear动画 3.点击自身或其他一级菜单,做逆操作 4.背景遮罩,使用ease-in/ease-out动画 步骤1 改造样式表,top值 步骤2 声明动画 核心代码: ``` animation: function(index) { // 定义一个动画 var animation = wx.createAnimation({ duration: 400, timingFunction: 'linear', }) // 是显示还是隐藏 var flag = this.data.subMenuDisplay[index] == 'show' ? 1 : -1; // flag = 1; console.log(flag) // 使之Y轴平移 animation.translateY(flag * (initSubMenuHighLight[index].length * 34) + 8).step(); // 导出到数据,绑定给view属性 this.setData({ animationData:animation.export() }); } ``` >完成动画后,需调用一次step(),不论是一组还是多组都需要调。 步骤3 声明data数组并与wxml绑定 ``` animationData: {} ``` wxml中 ```
``` >z-index问题,会挡住一级菜单,设置为-999,可以置于一级菜单之下 >使用bottom: 0;初始在一级菜单底边缘平齐。 >dl 设置为position: relative; 与二级菜单 position: absolute 对应。 步骤4 点击一级菜单调用动画 ``` // 设置动画 this.animation(index); ``` 步骤5 点击二级菜单调用动画 ``` // 设置动画 this.animation(indexArray[0]); ``` 步骤6 display属性要改为visibility ``` /* 显示与隐藏 */ .show { /*display: block;*/ visibility: visible; } .hidden { /*display: none;*/ visibility:hidden; } ``` >保留占位,宽度高度,不然点击没了动画效果。 源码下载:关注下方的公众号->回复数字1006 对小程序开发有趣的朋友关注公众号: huangxiujie85,QQ群: 575136499,微信: small_application,陆续还将推出更多作品。 ![公众号](https://static.oschina.net/uploads/img/201610/07111145_qD6d.jpg "二维码")