微信小程序之多级联动菜单

介绍

多级联动菜单在许多的筛选场景应用十分广泛。

动手操作

先看看效果图:


menu_full.gif
  • 总体布局

总体布局.png

menu.wxml

<view class="menu">
  <!-- 菜单导航 -->
  <view class="menu_navi">
    <view class="menu_navi_item" >
      <text>游戏</text>
    </view>
    <view class="menu_navi_item">
      <text>体育</text>
    </view>
    <view class="menu_navi_item">
      <text>电影</text>
    </view>
  </view>
  <!-- 某个菜单的内容 -->
  <view class="menu_content">
    <view class="menu_one">
      <scroll-view class="left">
        <view class="left_item">左边</view>
      </scroll-view>
      <scroll-view class="right">
        <view class="right_item">右边</view>
      </scroll-view>
    </view>
    <view class="menu_two" wx:if="{{menu_two_show}}">
      <scroll-view class="left">
        <view class="left_item">左边</view>
      </scroll-view>
      <scroll-view class="right">
        <view class="right_item">右边</view>
      </scroll-view>
    </view>
    <view class="menu_three" wx:if="{{menu_three_show}}">
      <scroll-view class="left">
        <view class="left_item">左边</view>
      </scroll-view>
      <scroll-view class="right">
        <view class="right_item">右边</view>
      </scroll-view>
    </view>
    <!-- 阴影部分 -->
    <view class="surplus"></view>

menu.wxss

.menu{
  position: fixed; /*固定位置*/
  top: 0rpx;
  left: 0rpx;
  width: 100%;
  display: flex;
  flex-direction: column;
}
  • 分模块进行开发

1、菜单导航

menu.jsp

<!--菜单导航-->
<view class="menu_navi">
  <view class="menu_navi_item {{ menu_one_show ? 'menu_select':''}}"  bindtap="menuOne" >
    <text>游戏</text>
    <icon class="iconfont {{ menu_one_show ? 'icon-unfold':'icon-fold'}}"></icon>
  </view>
  <view class="menu_navi_item {{ menu_two_show ? 'menu_select':''}}"  bindtap="menuTwo">
    <text>体育</text>
    <icon class="iconfont {{ menu_two_show ? 'icon-unfold':'icon-fold'}}"></icon>
  </view>
  <view class="menu_navi_item {{ menu_three_show ? 'menu_select':''}}"  bindtap="menuThree">
    <text>电影</text>
    <icon class="iconfont {{ menu_three_show ? 'icon-unfold':'icon-fold'}}"></icon>
  </view>
</view>

menu.wxss

.menu_navi{
  display: flex;
  flex-direction: row;
  width: 100%;
}

.menu_navi_item{
  display: flex;
  flex-direction: row;
  justify-content: center; /*主轴居中  水平*/
  align-items: center; /*侧轴居中 垂直*/
  border: 1rpx solid #DCDCDC;
  font-size: 30rpx;
  width: 35%;
  height: 80rpx;
}
/*菜单导航栏选中时,出现此样式*/
.menu_select{
  color: brown;
  background-color: springgreen;
}

menu.js

Page({
  data: {
    //游戏、体育、电影的显示与隐藏控制参数
    menu_one_show: false, //控制菜单一的内容
    menu_two_show: false, //控制菜单二的内容
    menu_three_show: false, //控制菜单三的内容
  },
/**
   * 选项卡的控制
   */
  //控制选项一
  menuOne: function () {
    var that = this;
    if (that.data.menu_one_show) { //说明menu_one_show现在展开,需要关闭
      that.setData({
        menu_one_show: false,
        menu_two_show: false,
        menu_three_show: false,
      })
    } else {
      that.setData({
        menu_one_show: true,
        menu_two_show: false,
        menu_three_show: false,
        select_left: select_left, //打开菜单的时候,默认选中的内容
        select_left_content: that.data.menu_one_data[select_left],
        select_right: '',
      })
    }
  },
  //控制选项二
  menuTwo: function () {
    var that = this;
    if (that.data.menu_two_show) {
      that.setData({
        menu_one_show: false,
        menu_two_show: false,
        menu_three_show: false,
      });
    } else {
      for (var select_top in that.data.menu_two_data) break; //第二个菜单栏的上部默认选中第一个,获得的是json的key值
      var select_top_content = that.data.menu_two_data[select_top]; //默认选中第一个后的内容,提供下面进行使用
      for (var select_left in select_top_content) break; //使用上面的内容,左边默认选中的第一个,而且也是获得它的key值,
      var select_top_content = select_top_content[select_left]; //默认选中左边的时候,右边的内容进行显示。
      that.setData({
        menu_one_show: false,
        menu_two_show: true,
        menu_three_show: false,
        select_top: select_top, //上方默认选择
        select_top_content: that.data.menu_two_data[select_top], //选中上方之后,下方的内容
        select_left: select_left, //左边的默认选择
        select_left_content: select_top_content, //选中左边之后的,右边的内容
      });
    }

  },
  //控制选项三
  menuThree: function () {
    var that = this;
    if (that.data.menu_three_show) {
      that.setData({
        menu_one_show: false,
        menu_two_show: false,
        menu_three_show: false,
      })
    } else {
      that.setData({
        menu_one_show: false,
        menu_two_show: false,
        menu_three_show: true,
        select_left: select_left, //同游戏那个菜单
        select_left_content: that.data.menu_three_data[select_left],
        select_right: '',
      })
    }
  },

2、多余部分

menu.wxml

<!-- 阴影部分 -->
    <view class="surplus" wx:if="{{(menu_one_show)||(menu_two_show)||(menu_three_show)}}" bindtap="menuFlod"></view>

menu.wxss

.menu .surplus{
  width: 100%;
  height: 500rpx;
  background-color: grey;
  opacity: 0.8;
}

menu.js

// 点击阴影部分,菜单隐藏
  menuFlod: function () {
    var that = this;
    that.setData({
      menu_one_show: false,
      menu_two_show: false,
      menu_three_show: false,
    })
  },

4、具体菜单内容

这里主要针对一个菜单栏进行详细讲解,其余两个原理相同。
游戏
menu.wxml

<!-- 选项一 -->
<view class="menu_content">
  <view class="menu_one" wx:if="{{menu_one_show}}">
    <scroll-view class="left" scroll-y="true">
      <view class="left_item {{select_left == key? 'select_left':''}} " wx:for="{{menu_one_data}}" wx:for-index="key" data-index="{{key}}" data-navi="1" wx:key="{{key}}" bindtap="selectLeft">
        <text>{{key}}</text>
      </view>
    </scroll-view>
    <scroll-view class="right" scroll-y="true">
      <view class="right_item {{select_right == item? 'select_right':''}}" wx:for="{{select_left_content}}" data-index="{{item}}" wx:key="{{item}}" bindtap="selectRight">
        <text>{{item}}</text>
      </view>
    </scroll-view>
  </view>
</view>

这里推荐大家使用<scroll-view></scroll-view>组件,这样超过限定的高度的话,就可以在内部产生滚动条,整体布局不会乱。使用<scroll></scroll>组件的时候,记得要开启滚动的方向(scroll-y表示纵向,scroll-x表示横向),这些属性默认是关闭的。
menu.wxss

.menu_content{
  width: 97.3%;
  margin: 10rpx;
  background-color: white;
}

.menu_one{
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 600rpx;
}

..menu_one .left{
  display: flex;
  flex-direction: column;
  width: 50%;
}

.menu_one .left .left_item{
  padding: 15rpx;
  line-height: 60rpx; /*设置成line-height自动垂直居中*/
}

.menu_one .left .select_left{
  color: rgb(235, 79, 79);
  background-color: #DCDCDC;
}

.menu_one .right{
  display: flex;
  flex-direction: column;
  width: 50%;
}

.menu_one .right .right_item{
  padding: 15rpx;
  line-height: 55rpx;
  background-color: #DCDCDC;
}

.menu_one .right .select_right{
  color: rgb(235, 79, 79);
}

注意:使用竖向滚动时,需要给<scroll-view/>一个固定高度,通过 WXSS 设置 height。
menu.js

data: {
    menu_one_data: {
      "热门": ['冒险岛', '恋爱', '泡泡堂', '僵尸', '哆啦A梦', '海绵宝宝', '喜羊羊与灰太狼', '经营', '射击', '坦克', '合金弹头', '棋牌', '巧虎', '斗地主', '麻将', '女生' ,'拳皇', '森林冰火人'],
      "益智": ['连连看', 'TD防守', '无敌连连看', '找茬', '模拟城市', '接水管', '斗地主', 'Nitrome', '对对碰', '华容道', '喜洋洋与灰太狼', '泡泡堂', '寻找小白人', '俄罗斯方块'],
      "冒险": ['乖乖猪世界', '灵动', '男生', '魔域', '智能火柴人', '武林外传', '小王子冒险岛', '外星人大冒险', '神刀传奇', '小小冒险岛', '肥猫天使', '黑暗僵尸仓库', '救人', '蜘蛛侠'],
      "战争": ['黑暗基地', '战争', '柏林飞机战争', '魔兽战争', '射击', '史诗幻想战役', '第一次世界大战', '合金弹头系列', '忍者与海盗', '火柴人战争', '冒险王', '午夜僵尸大战', '金刚狼'],
      "动作": ['变态版', '松鼠大决战', '李小龙', '中国功夫', '明星大乱斗', '疯狂独轮车大战', '海绵宝宝空手道', '兔子杀戮', '拳皇wing', '悟空格斗', '火影忍者大乱斗', '泰拳小子'],
      "敏捷": ['小鸟', '神奇小妖怪相关', '冒险', '死神', '祖玛', '暴力拆除', '洛克人', '索尼克', '森林冰火人', '植物大战僵尸相关', '模拟世界', '冒险岛', '黄金矿工', '动作', '三国'],
      "女生": ['化妆', '换装', '打扮', '宝贝', '发型设计', '芭比娃娃', '明星' ,'爱情测试', '甜心姐妹美发', '婚礼婚纱', '精灵换装', '恋爱', '礼服' ,'可爱', '模拟世界', '开店经营' ,'设计布置', '美女'],
      "专辑": ['动漫', '游戏', '哆啦A梦', '冒险岛系列', '虹猫蓝兔', '火影忍者' ,'少年骇客', '蜡笔小新', '史酷比系列', '蝙蝠侠', '降世神通Avatar', '海贼王系列' ,'拼图' ,'儿童', '西游记', '洛克人']
    },
    menu_three_data:{
      "喜剧": ['憨豆先生精选辑', '美丽人生', '福尔摩斯二世', '顺其自然', '摩登时代', '城市之光', '三傻大闹宝莱坞', '疯狂动物城', '大话西游', '寻子遇仙记', '淘金记'],
      "爱情": ['霸王别姬', '阿甘正传', '美丽人生', '泰坦尼克号', '巴黎圣母院', '罗密欧与朱丽叶', '我爱你', '断背山', '请以你的名字呼唤我', '幸福终点站'],
      "科幻": ['盗梦空间', '星际穿越', '虚幻勇士', '蝙蝠侠:黑暗骑士', '楚门的世界', 'V字仇杀队', '黑客帝国', '蝴蝶效应', '人工智能'],
      "纪录片": ['人生果实', '人生七年', '从纳粹手中救出的孩子们', '克拉玛依'],
      "家庭": ['东京物语', '灿烂人生', '摔跤吧!爸爸', '我的父亲,我的儿子', '地上的星星', '大鱼', '金色池塘', '岁月神偷'],
      "战争": ['辛德勒的名单', '战争与和平3', '鬼子来了', '沉静如海', '革命往事', '法国大革命', '拯救大兵瑞恩', '勇敢的心', '乱'],
    },
    select_left: '', //默认选中左边框的内容 (选中哪一项)
    select_left_content:[], //选中左边框--->右边框的内容
    select_right: '', //默认选中右边框边框的内容 (选中哪一项)
  },
/**
   * 点击左边框
   */
  selectLeft: function (e) {
    var that = this;
    var select_left = e.currentTarget.dataset.index; //从wxml中传过来的数据,表示选中那个key
    var select_left_content = []; //准备接收右边的内容
    // 判断是哪个菜单栏
    if ('1' == e.currentTarget.dataset.navi){
      select_left_content = that.data.menu_one_data[select_left];
    } else if ('2' == e.currentTarget.dataset.navi){
      select_left_content = that.data.select_top_content[select_left];
    } else {
      select_left_content = that.data.menu_three_data[select_left];
    }
    console.log(select_left_content);
    that.setData({
      select_left: select_left,
      select_left_content: select_left_content,
      select_right: '',
    })
  },
  /**
   * 点击右边框
   */
  selectRight: function(e){
    var that = this;
    var select_right = e.currentTarget.dataset.index;
    that.setData({
      select_right: select_right
    })
  },

menu.js部分主要的难点就是wxml和js之间的数据交互,这里很容易弄晕,尤其是对自己定义的变量弄清楚是什么意思。在这里小编画了一个示意图来讲解这个难点。


菜单中的控制显示

最后给大家提供该项目的github项目,直接抓下来就可以打开使用,只需对显示的数据进行修改即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容

  • 1.小程序起步 (1)点击https://mp.weixin.qq.com/wxopen/waregister?a...
    GXW_Lyon阅读 3,326评论 0 0
  • 每天的学习记录,可能有的地方写的不对,因为刚学,以后发现错的话会回来改掉整体流程 https://develope...
    有点健忘阅读 4,644评论 0 7
  • 前言 微信之父张小龙在年初的那次演讲中曾表示:“我自己是很多年的程序员,我觉得我们应该为开发的团队做一些事情”。几...
    4638d5195a5f阅读 1,378评论 0 2
  • 因新工作主要负责微信小程序这一块,最近的重心就移到这一块,该博客是对微信小程序整体的整理归纳以及标明一些细节点,初...
    majun00阅读 7,332评论 0 9
  • 祺和楠是一所普通高中的同学,那时的他们并不熟悉,在祺眼里,楠是个羞涩的女生,不爱说话,总是坐在班里的后面低着...
    希漪阅读 125评论 0 0