头图

微信小程序(四)绝对不可错过切换自定义菜单栏的骚操作

前言

在开发小程序的时候,一般的小程序用官方自带的菜单栏就够了,但一但稍微复杂的小程序可能因为产品经理的一句“页面太多了得加个菜单”,就可能要对菜单栏进行增、删、改的操作,这个时候自带的就满足不了需求了,可以使用官方提供的自定义菜单栏。

但官方提供的自定义菜单栏有个特点,就是菜单栏的页面必须是 Component ,假如你是在项目做到一半的时候有要对菜单栏进行增、删、改的需求,用官方提供自定义菜单栏就需要把page页面改成 Component,那就需要很多时间修改页面逻辑,会很麻烦。

所以这个时候,我们就可以采用官方自带的菜单栏和自己封装的菜单栏组合使用,这样能节省修改逻辑的时间,还能享受自带菜单的良好交互。

思路

我们可以用小程序自带的菜单和我们自己封装的自定义菜单组件使用,具体逻辑是这样的:

  • 我们先可以在全局 app.js 文件的全局变量 globalData 里定义一个区分展示自定义菜单还是官方自带菜单的变量 tabbar_type
  • 通过 tabbar_type 在每个菜单页面区分展示官方自带的菜单栏还是自己封装的自定义菜单栏
  • 当展示自定义菜单栏的时候调用官方提供的 api 隐藏官方自带的菜单栏。当展示官方菜单栏的时候,通过修改全局变量 tabbar_type 的值来隐藏自定义菜单栏

成品效果

20220630_223645.gif

具体实现

先在 app.json 页面配置好官方自带的菜单栏

  "tabBar": {
    "custom": false,
    "color": "#999999",
    "selectedColor": "#00C3B3",
    "borderStyle": "black",
    "backgroundColor": "#f8f8f8",
    "list": [
      {
        "selectedIconPath": "/assets/img/homeActive.png",
        "iconPath": "/assets/img/home.png",
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "selectedIconPath": "/assets/img/mallActive.png",
        "iconPath": "/assets/img/mall.png",
        "pagePath": "pages/index/index",
        "text": "商城"
      },

      {
        "selectedIconPath": "/assets/img/myActive.png",
        "iconPath": "/assets/img/my.png",
        "pagePath": "pages/index/index",
        "text": "我的"
      }
    ]
  },

然后封装一个自定义的菜单栏组件

目录结构:

+ components
  + shoping-tabbar
    - index.js
    - index.json
    - index.wxml
    - index.wxss

index.js 文件代码

// components/shoping-tabbar/index.js
const app = getApp();
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    selected: {
      type: Number,
      default: 0
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    selectedIndex: 0,
    color: "#999999",
    selectedColor: "#00C3B3",
    list: [
      {
        "selectedIconPath": "/assets/img/mallActive.png",
        "iconPath": "/assets/img/mall.png",
        "pagePath": "/pages/index/index",
        "text": "商城"
      },
      {
        "selectedIconPath": "/assets/img/cartActive.png",
        "iconPath": "/assets/img/cart.png",
        "pagePath": "/pages/index/index",
        "text": "购物车"
      },
      {
        "selectedIconPath": "/assets/img/orderActive.png",
        "iconPath": "/assets/img/order.png",
        "pagePath": "/pages/index/index",
        "text": "订单"
      }
    ]
  },

  attached: function () {
    this.setData({
      selectedIndex: this.properties.selected
    })
  },
  /**
   * 组件的方法列表
   */
  methods: {
    switchTab(e) {
      let data = e.currentTarget.dataset
      let url = data.path
      wx.redirectTo({
        url,
        fail: function (err) {
          wx.switchTab({
            url
          })
        },
        success: () => {
          this.setData({
            selectedIndex: data.index
          })
        }
      })
      wx.hideTabBar({
        animation: false,
        success: () => {
          app.globalData.tabbar_type = 2
        }
      })
    }
  },
})

index.wxml 文件

<view class="tab-bar">
  <view class="tab-bar-border"></view>
  <view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
    <image src="{{selectedIndex === index ? item.selectedIconPath : item.iconPath}}"></image>
    <view style="color: {{selectedIndex === index ? selectedColor : color}}">{{item.text}}</view>
  </view>
</view>

然后在需要自定义菜单组件的页面引入

selected 为菜单的序号,比如成品效果动态图中的自定义菜单分别有商城、购物车、订单三个页面,序号分别为1,2,3。

<nav-tabar selected="{{selected}}" wx:if="{{tabbar_type==2}}"></nav-tabar>

然后在自定义菜单栏页面(商城、购物车、订单)的 onShow() 方法里分别初始化是否显示菜单的变量

this.setData({
  tabbar_type: app.globalData.tabbar_type
})

最后一步很关键,通过上面的成品效果动态图可以看到,从官方自带的菜单栏跳我们封装的自定义菜单栏的页面,是通过 商城 这个页面中转的,这个页面比较特别,它既是官方自带的菜单中的一个页面,又用了我们自己封装的自定义菜单栏组件。

我们可以通过官方提供的 onTabItemTap() 来监听,当展示官方菜单栏且点击这个tab页的时候就隐藏官方的菜单栏,展示自己封装的自定义菜单栏。

  /**
   * 当前是 tab 页时,点击 tab 时触发
   * @param {*} item 
   */
  onTabItemTap(item) {
    wx.hideTabBar({
      animation: false,
      success: () => {
        this.setData({
          tabbar_type: 2
        })
        app.globalData.tabbar_type = 2
      }
    })
  },

然后在这个中转页商城页的返回事件这样处理:隐藏自己封装的菜单栏,展示官方的菜单栏

  navToBack() {
    let pages = getCurrentPages();
    // 获取前一个页面的路径
    let prevpageHtml = pages[0].__displayReporter.showReferpagepath;
    wx.showTabBar({
      animation: true,
      success: () => {
        wx.switchTab({
          url: `/${prevpageHtml.substring(0, prevpageHtml.lastIndexOf('.html'))}`,
        })
        this.setData({
          tabbar_type: 1
        })
        app.globalData.tabbar_type = 1;
      }
    })

  },

总结

用官方自带的菜单栏和自己封装的自定义菜单栏组合使用的好处就是既能享受官方自带菜单栏的友好交互,有能把中途因需求原因改菜单栏需将 tabbar页 从 page 改成 component 的时间省下。这样的骚操作在这种情况还是很可行的,哈哈。

话说时间过得真快呀,再过35分钟就是下半年的第一天了,祝大家都有个好的下半场开端吧!

写在最后

我是 AndyHu,目前暂时是一枚前端搬砖工程师。

文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注呀😊

未经许可禁止转载💌

speak less,do more.

17 声望
0 粉丝
0 条评论
推荐阅读
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs40阅读 4.8k评论 5

封面图
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -&gt; Preference-&gt; Settings(如果装了中文插件包应该是 文件 -&gt; 选项 -&gt; 设置),搜索 eslint,点击 Edit in setting.json

谭光志34阅读 20.8k评论 9

安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城32阅读 7.3k评论 5

封面图
vue UI框架比较
最好基于vue2.0PC端:因为用过的是饿了么UI,所以比较以饿了么UI为基础element UI 饿了么UI支持vue2.x80分优点:组件的API方法、属性等封装的较为完善缺点:样式有些生硬,不够炫酷美观N3 N3支持vue2.x70分优点:...

chinawzc22阅读 39.9k评论 17

涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco24阅读 2.3k评论 3

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 2k

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.8k评论 3

封面图
17 声望
0 粉丝
宣传栏