精华内容
下载资源
问答
  • 微信小程序自定义tabBar

    万次阅读 2019-07-17 10:47:41
    本文分享一下微信小程序自定义tabBar的几种实现方式。

    本文分享一下微信小程序自定义tabBar的几种实现方式。

    模拟的tabBar页面(不推荐)

    使用策略

    • app.json不配置tabBar,用普通page来代替tabbar页面,暂且称之为模拟的tabbar页面。

      tabbar效果图1

    • 每个模拟的tabbar页面都需要引入自定义tabbar组件。

    1. 自定义的tabbar组件写法如下:

    /components/index-tabbar/index.json

    {
      "component": true,
      "usingComponents": {
        "van-tabbar": "vant-weapp/tabbar/index",
        "van-tabbar-item": "vant-weapp/tabbar-item/index"
      }
    }
    

    /components/index-tabbar/index.wxml

    <cover-view class="container">
      <van-tabbar active="{{ active }}" bind:change="onChange">
        <van-tabbar-item name="index" icon="home-o">首页</van-tabbar-item>
        <van-tabbar-item name="category" icon="label-o">分类</van-tabbar-item>
        <van-tabbar-item name="msgs" icon="comment-o">留言</van-tabbar-item>
        <van-tabbar-item name="my" icon="user-o">我的</van-tabbar-item>
      </van-tabbar>
    </cover-view>
    
    

    /components/index-tabbar/index.js

    Component({
      properties: {
        active: {
          type: String,
          value: 'index'
        },
      },
      methods: {
        onChange(event) {
          wx.redirectTo({
            url: `/pages/${event.detail}/index`,
          })
        }
      }
    })
    
    1. 模拟的tabbar页面写法如下:

    /pages/home/index.json

    {
      "usingComponents": {
        "index-tabbar": "/components/index-tabbar/index"
      }
    }
    

    /pages/home/index.wxml

    <view class="container">
      <text>首页</text>
      <index-tabbar active="index"></index-tabbar>
    </view>
    
    • 跳转页面使用wx.redirectTo

    总结

    由于wx.redirectTo跳转页面是跳转的普通页面,页面渲染也自然会导致自定义的tabbar组件重新渲染,所以会出现底部tabbar闪一下的视觉体验,很尴尬。

    Component伪装Page(还不错)

    使用策略

    将上述4个模拟的tabBar页面换成组件写法,然后根据条件进行wx:if控制。

    1. 改造首页,分类,留言,我的,将其由页面改为组件

    /pages/home/index.json

    {
      "component": true
    }
    

    /pages/home/index.wxml

    <view>
      <text>首页</text>
    </view>
    

    /pages/home/index.js

    Component({})
    
    1. index-tabbar组件改造

    /components/index-tabbar/index.wxml

    <cover-view class="container">
      <van-tabbar active="{{ active }}" bind:change="onChange">
        <van-tabbar-item
          wx:for="{{panels}}"
          wx:for-index="index"
          wx:for-item="item"
          wx:key="{{index}}"
          name="{{item.name}}"
          icon="{{item.icon}}"
          info="{{item.badge}}">
          {{item.label}}
        </van-tabbar-item>
      </van-tabbar>
    </cover-view>
    
    
    

    /components/index-tabbar/index.js

    Component({
      properties: {
        active: {
          type: String,
          value: 'home'
        },
        panels: {
          type: Array,
          value: []
        },
      },
      methods: {
        onChange(event) {
          this.triggerEvent('changeTab', event.detail)
        }
      }
    })
    
    
    
    1. 入口页index改写成如下

    /pages/index/index.json

    {
      "usingComponents": {
        "index-tabbar": "/components/index-tabbar/index",
        "home-panel": "../home/index",
        "category-panel": "../category/index",
        "msgs-panel": "../msgs/index",
        "my-panel": "../my/index"
      }
    }
    
    

    /pages/index/index.wxml

    <view class="container">
      <home-panel wx:if="{{activeTab == 'home'}}">首页</home-panel>
      <category-panel wx:if="{{activeTab == 'category'}}">分类</category-panel>
      <msgs-panel wx:if="{{activeTab == 'msgs'}}">留言</msgs-panel>
      <my-panel wx:if="{{activeTab == 'my'}}">我的</my-panel>
      <index-tabbar active="{{activeTab}}" panels="{{panels}}" bind:changeTab="onTabChange"></index-tabbar>
    </view>
    
    
    

    /pages/index/index.js

    Page({
      data: {
        activeTab: 'home',
        panels: [
          { name: 'home', icon: 'home-o', label: '首页' },
          { name: 'category', icon: 'label-o', badge: '5', label: '分类' },
          { name: 'msgs', icon: 'comment-o', badge: '99+', label: '留言' },
          { name: 'my', icon: 'user-o', label: '我的' }
        ]
      },
      onTabChange(event) {
        this.setData({
          activeTab: event.detail
        })
      }
    })
    
    
    

    效果如下:

    tabbar效果图2

    总结

    由于是通过wx:if控制组件的创建和销毁,是局部更新,所以不会导致底部tabbar的重新渲染,所以底部闪一下的问题就解决了。缺点我想是如果频繁切换tab可能导致wx:if的渲染开销大吧。

    官方自定义tabBar

    官方也提供了自定义tabbar的方法,见自定义 tabBar

    基础库 2.5.0 开始支持,低版本需做兼容处理

    首发链接

    关注我

    展开全文
  • 微信小程序自定义tabbar【内有点击和滑动两种方式】 ...
  • 微信小程序 自定义tabbar

    千次阅读 2018-08-08 17:12:39
    ## 微信小程序 自定义tabbar [项目地址,欢迎 star](https://github.com/songzeng2016/wechat-app-tabbar)  [https://github.com/songzeng2016/wechat-app-tabbar]...

    首发于掘金,点击查看

    ## 微信小程序 自定义tabbar

    [项目地址,欢迎 star](https://github.com/songzeng2016/wechat-app-tabbar) 

    [https://github.com/songzeng2016/wechat-app-tabbar](https://github.com/songzeng2016/wechat-app-tabbar)


    ### 前言

    项目中我们可能会用到两层 tabbar 而小程序只能配置出一层,或者我们想自定义 tabbar 的样式或功能,这时候就需要我们自己定义 tabbar。
    先来张图看下效果,下面是实现步骤。

    ![tabbar.gif](https://user-gold-cdn.xitu.io/2018/5/4/16328c81d6c2d9e6?w=396&h=710&f=gif&s=39373)


    ### 创建wxml模板

    ```html
    <template name="tabbar">
        <view class="tabbar_box" style="background-color:{{tabbar.backgroundColor}}; border-top-color:{{tabbar.borderStyle}}; {{tabbar.position == 'top' ? 'top:0' : 'bottom:0'}}">
            <block wx:for="{{tabbar.list}}" wx:for-item="item" wx:key="index">
                <navigator class="tabbar_nav" url="{{item.pagePath}}" style="width:{{1/tabbar.list.length*100}}%; color:{{item.selected ? tabbar.selectedColor : tabbar.color}}" open-type="redirect">
                    <image class="tabbar_icon" src="{{item.selected ? item.selectedIconPath : item.iconPath}}"></image>
                    <text>{{item.text}}</text>
                </navigator>
            </block>
        </view>
    </template>
    ``` 
    ### wxss布局

    ```css
    .tabbar_box{
        display: flex;
        flex-direction: row;
        justify-content: space-around;
        position: fixed;
        bottom: 0;
        left: 0;
        z-index: 999;
        width: 100%;
        height: 120rpx;
        border-top: 1rpx solid gray; 
    }

    .tabbar_nav{
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        font-size: 28rpx;
        height: 100%;
    }

    .tabbar_icon{
        width: 61rpx;
        height: 61rpx;
    }
    ```
        布局不是重点也可以自定义布局也可以引用我写好的样式

    ### 重点来了 tabbar的参数配置

    ```javascript
    tabbar:{
          color: "#000000",
          selectedColor: "#0f87ff",
          backgroundColor: "#ffffff",
          borderStyle: "black",
          list: [
            {
              pagePath: "/pages/tabbar/tabbar",
              text: "项目",
              iconPath: "/images/item.png",
              selectedIconPath: "/images/item_HL.png",
              selected: true
            },
            {
              pagePath: "/pages/address/address",
              text: "通讯录",
              iconPath: "/images/ts.png",
              selectedIconPath: "/images/ts1.png",
              selected: false
            },
            {
              pagePath: "/pages/personal/personal",
              text: "文件",
              iconPath: "/images/wjj.png",
              selectedIconPath: "/images/wjj1.png",
              selected: false
            }
          ],
          position: "bottom"
        }
        
    ```
        有没有感觉很熟悉,没错就是你熟悉的tababar配置,仅仅增加了一个selected参数来表示选中的状态
        另外一点要注意的是我们的tabbar数据配置在app.js里面而不是app.json里面
        
    ### 最后还有一个比较重要的点 在app.js里面的一个函数
    ```javascript
    editTabBar: function(){
        var tabbar = this.globalData.tabbar,
            currentPages = getCurrentPages(),
            _this = currentPages[currentPages.length - 1],
            pagePath = _this.__route__;
        (pagePath.indexOf('/') != 0) && (pagePath = '/' + pagePath);
        for(var i in tabbar.list){
          tabbar.list[i].selected = false;
          (tabbar.list[i].pagePath == pagePath) && (tabbar.list[i].selected = true);
        }
        _this.setData({
          tabbar: tabbar
        });
      },
    ```
    ### 我们完整的app.js是这样的
    ```javascript
    //app.js
    App({
      onLaunch: function () {
        //调用API从本地缓存中获取数据
        var logs = wx.getStorageSync('logs') || []
        logs.unshift(Date.now())
        wx.setStorageSync('logs', logs)
      },
      getUserInfo:function(cb){
        var that = this
        if(this.globalData.userInfo){
          typeof cb == "function" && cb(this.globalData.userInfo)
        }else{
          //调用登录接口
          wx.login({
            success: function () {
              wx.getUserInfo({
                success: function (res) {
                  that.globalData.userInfo = res.userInfo
                  typeof cb == "function" && cb(that.globalData.userInfo)
                }
              })
            }
          })
        }
      },
      editTabBar: function(){
        var tabbar = this.globalData.tabbar,
            currentPages = getCurrentPages(),
            _this = currentPages[currentPages.length - 1],
            pagePath = _this.__route__;
        (pagePath.indexOf('/') != 0) && (pagePath = '/' + pagePath);
        for(var i in tabbar.list){
          tabbar.list[i].selected = false;
          (tabbar.list[i].pagePath == pagePath) && (tabbar.list[i].selected = true);
        }
        _this.setData({
          tabbar: tabbar
        });
      },
      globalData:{
        userInfo:null,
        tabbar:{
          color: "#000000",
          selectedColor: "#0f87ff",
          backgroundColor: "#ffffff",
          borderStyle: "black",
          list: [
            {
              pagePath: "/pages/tabbar/tabbar",
              text: "项目",
              iconPath: "/images/item.png",
              selectedIconPath: "/images/item_HL.png",
              selected: true
            },
            {
              pagePath: "/pages/address/address",
              text: "通讯录",
              iconPath: "/images/ts.png",
              selectedIconPath: "/images/ts1.png",
              selected: false
            },
            {
              pagePath: "/pages/personal/personal",
              text: "文件",
              iconPath: "/images/wjj.png",
              selectedIconPath: "/images/wjj1.png",
              selected: false
            }
          ],
          position: "bottom"
        }
      }
    })
    ```
        生成的东西我没有删掉
        
    ### 到这准备工作已经完成  下面就是怎么使用

    #### 在wxml引入创建的模板并使用
    ```html
    <import src="../tabbar/tabbar.wxml"/>
    <template is="tabbar" data="{{tabbar}}"/>

    ```
        我这里是相对路径,最好写成绝对路径
        
    #### wxss中引入样式
    ```css
    @import "/pages/tabbar/tabbar.wxss"

    ```

    #### js中调用函数

    ```javascript
    //获取app实例
    var app = getApp();

    Page({
      data:{
        tabbar:{}
      },
      onLoad:function(options){
        // 页面初始化 options为页面跳转所带来的参数
        
        //调用函数
        app.editTabBar(); 
      },
      onReady:function(){
        // 页面渲染完成
      },
      onShow:function(){
        // 页面显示
      },
      onHide:function(){
        // 页面隐藏
      },
      onUnload:function(){
        // 页面关闭
      }
    })
    ```

        注意在每个配置在tabbar中的页面都要有这三步,因为这个是页面跳转了
        还有一个问题就是页面跳转的时候会闪一下,网络慢的时候更明显
        后面我会做一个不是跳转页面的tabbar
        
    不跳转页面的暂时还没有更好的思路先给大家推荐一个  [不跳转页面的tabbar](https://github.com/marlti7/wx-mina-custom-tabbar)

    [微信小程序仿微信, QQ 向左滑动删除操作](https://github.com/songzeng2016/wechat-app-LeftSlide)

    [微信小程序 自定义tabbar](https://github.com/songzeng2016/wechat-app-tabbar)
     

    展开全文
  • 主要为大家详细介绍了微信小程序自定义tabBar组件开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • wx-mina-custom-tabbar 微信小程序自定义tabbar,包含可左右滚动。
  • 微信小程序自定义 tabBar微信小程序自定义 tabBar先简单介绍一下微信官方提供的自定义tabBar 的用法实际使用中出现问题?自助自定义tabBar组件实现custom-tab-bar 代码页一起奉上 微信小程序自定义 tabBar 基础库 ...

    微信小程序自定义 tabBar

    基础库 2.5.0 开始支持,低版本需做兼容处理。
    微信小程序基础库 2.5.0 开始微信官方开放自定义底部 tabBar 组件 。主要是为了让开发者可以更加灵活地设置 tabBar 样式,以满足更多个性化的场景。但是在实际开发者使用微信官方提供的组件 , 适配和兼容并不感人 , 让人从满怀希望到绝望 ;

    先简单介绍一下微信官方提供的自定义tabBar 的用法

    在 app.json 中的 tabBar 项指定 custom (布尔值)字段,在所有 tab 页的 json 里需声明 usingComponents 项,也可以在 app.json 全局开启。在根目录下创建custom-tab-bar/index.js custom-tab-bar/index.json custom-tab-bar/index.wxml custom-tab-bar/index.wxss具体页面代码不在书写 , 可在 tabBar 组件底部示例代码中点击 在开发者工具中预览效果 在编辑器中拷贝相关代码即可;

    实际使用中出现问题?
    在使用官方提供的自定义tabBar 组件中 , 点击切换tabBar时 , 点击切换选中的状态一直是上一次(上一个tabBar)点击的tabBar , 并且首次点击切换到其他tabBar页是会有闪烁现象 ; 在微信社区和博客中尝试很多方法 , 都没有能解决问题 , 最后不得放弃使用 , 自己从新自定义一个tabBar组件 ;

    自助自定义tabBar组件实现

    1.在app.js中 onLaunch 中 调用 wx.hideTabBar() 方法隐藏tab , 或者在第2步新建的 custom-tab-bar目录中index.js生命周期attached中调用 wx.hideTabBar() 方法隐藏tab; 注意基础库 1.9.0开始支持 , 全局变量globalData 中增加 selectedIndex:0 ;
    2. 新建components目录 , 在components目录中创建 custom-tab-bar目录 custom-tab-bar目录中分别新建index.wxml , index.js ,index.json , index.wxss页面 ; 注意要在index.json 设置 component": true;
    3. 在tabBar页面中引用组件 .json页中设置 "usingComponents": { "custom-tab-bar": "/components/custom-tab-bar/index" }
    4. .wxml页面中使用 tabBar组件<custom-tab-bar></custom-tab-bar>

    custom-tab-bar 代码页一起奉上

    index.wxml页面

    <cover-view class="tab-bar" style="background:{{items.style.background}}">
      <cover-view class="tab-bar-border"></cover-view>
      <cover-view wx:for="{{items.data}}" wx:key="*this" class="tab-bar-item" data-path="{{item.linkUrl}}" data-index="{{index}}" bindtap="switchTab" wx:for-index="index">
        <cover-image src="{{selected === index ? item.select_imgUrl : item.default_imgUrl}}"></cover-image>
        <cover-view style="color: {{selected === index ? item.select_color : item.color}}">{{item.text}}</cover-view>
      </cover-view>
    </cover-view>
    

    index.wxss页面

    .tab-bar {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      height: 48px;
      background: white;
      display: flex;
      padding-bottom: env(safe-area-inset-bottom);
    }
    
    .tab-bar-border {
      background-color: rgba(0, 0, 0, 0.33);
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 1px;
      transform: scaleY(0.5);
    }
    
    .tab-bar-item {
      flex: 1;
      text-align: center;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
    }
    
    .tab-bar-item cover-image {
      width: 27px;
      height: 27px;
    }
    
    .tab-bar-item cover-view {
      font-size: 10px;
    }
    
    

    index.js页面

    const App = getApp();
    Component({
      lifetimes: {
        attached: function () {
          wx.hideTabBar();
          this.getTab();
        },
        ready: function () {
          this.setData({
            selected: App.globalData.selectedIndex
          });
        }
      },
      
      data: {
        selected: 0, // 当前 tabBar 索引 
        color: "#6e6d6b",
        selectedColor: "#fd4a5f",
        borderStyle: "black",
        backgroundColor: "#ffffff",
        items: [], //.wxml items 渲染数据
        //tabBar items(如下list字段)示例
        list: {
        	data:[{
    			color: "#666666"
    			default_imgUrl: "https://www.jinnong.com/uploads/202102021028438faa49673.png"
    			linkUrl: "pages/index/index"
    			select_color: "#f44336"
    			select_imgUrl: "https://www.jinnong.com/uploads/2021020210284341feb1488.png"
    			text: "首页"
    		},{
    			color: "#666666"
    			default_imgUrl: "https://www.jinnong.com/uploads/20210202102843feecc5864.png"
    			linkUrl: "pages/customtabbar/index?page_id=10125"
    			select_color: "#f44336"
    			select_imgUrl: "https://www.jinnong.com/uploads/202102021028438b66c5733.png"
    		},{
    			color: "#666666"
    			default_imgUrl: "https://www.jinnong.com/uploads/20210202102843468f98837.png"
    			linkUrl: "pages/flow/index"
    			select_color: "#f44336"
    			select_imgUrl: "https://www.jinnong.com/uploads/20210202102843559327043.png"
    			text: "购物车"
    		},{
    			color: "#666666"
    			default_imgUrl: "https://www.jinnong.com/uploads/202102021028438faa49673.png"
    			linkUrl: "pages/user/index"
    			select_color: "#f44336"
    			select_imgUrl: "https://www.jinnong.com/uploads/2021020210284341feb1488.png"
    			text: "我的"
    		}],
    		name: "导航组",
    		type: "navBar",
    		style: {
    			background: "#ffffff"
    			rowsNum: "4"
    		}
        }
      },
      methods: {
      	/**
         * tabBar切换
         */
        switchTab(e) {
          const data = e.currentTarget.dataset;
          const url = data.path;
          App.navigationTo(url);
          App.globalData.selectedIndex = data.index;
        },
        /**
         * 后台接口获取tabBar数据
         */
        getTab(){
          let _this = this;
          App._get('page/nav', {}, function(res) {
            const items = res.data.items;
            _this.setData({items})
          });
        }
      }
    })
    

    index.json页面

    {
      "component": true
    }
    

    注:实际项目中使用点击切换tabBar时会项存item下标指向问题,需要结合自己的项目数据结构做js逻辑处理显示(后续完整解决方法会文章形式补充~~)

    好用 , 方便点下收藏 , 不迷路 ! ! !

    展开全文
  • 主要介绍了微信小程序自定义tabBar在uni-app的适配详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • tabBar 微信小程序自定义tabBar tabBar兼容 微信小程序tabBar兼容低版本 自定义组件tabBar 自定义tabBar

    参考文档

    小程序官方的tabBar文档
    小程序官方的Component文档
    小程序app.json的配置

    注意事项

    1. 自定义tabBar 基础库 2.5.0 开始支持
    2. 自定义tabBar的组件一定要叫 custom-tab-bar 并且一定要与app.js同级
    3. 在 app.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置也补充完整。
    4. 所有 tab 页的 json 里需声明usingComponents 项,也可以在 app.json 全局开启。
    // app.json 记得删掉注释
    
      "usingComponents": {
        "nav": "/components/nav_bar/nav_bar" // 用与做低版本适配的 自定义tabBar组件
      },
      "tabBar": {
        "custom": true, // 打开tabBar的自定义功能
        "color": "#212121",
        ...
    

    项目结构

    • 代替原生tabBar的 custom-tab-bar 是不是一定要这样放?
      是的,一定要放在与app.js同级的项目结构, 而且一定要叫 custom-tab-bar
      微信小程序自定义tabBar 项目结构

    先码为敬

    custom-tab-bar

    1、/custom-tab-bar/index.wxml

    <!--components/custom-tab-bar/index.wxml-->
    <view class='my-bar ak-flexB {{isIpx ? "hackIPX" : ""}}'>
      <view wx:for="{{list}}" wx:key="index" class='my-bar__item ak-flexC' data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab" data-jump_type='{{item.jumpType}}'>
        <view class='my-bar__item-text ak-flex-columnC {{selected == index ? "my-bar__item-active" : ""}}'>
          <image class='my-bar__btn-img animated' mode='widthFix' src='{{selected === index ? item.selectedIconPath : item.iconPath}}'></image>
          {{item.text}}
          <view hidden="{{item.tagNum <= 0}}" class='my-bar__item-tag ak-flexC'>
            {{item.tagNum}}
          </view>
        </view>
      </view>
    </view>
    

    2、/custom-tab-bar/index.js

    // components/custom-tab-bar/index.js
    let app = getApp();
    Component({
      /**
       * 组件的属性列表
       */
      properties: {
        now: {
          type: String,
          value: 'index'
        },
        cartNum: {
          type: Number,
          value: 0,
        }
      },
    
      /**
       * 组件的初始数据
       */
      data: {
        isIpx: app.globalData.isIpx,  // 用于适配全面屏的底部高度(iPhone X* 的底部杠杠)
        selected: 0, // 当前选中的项
        color: "#333", // 未选中的字体的颜色
        selectedColor: "#d01716", // 选中时的字体颜色
        list: [{
          pagePath: "/pages/index/index", // 跳转路径, 【switchTab的跳转一定要在app.json中配置】
          iconPath: "/images/icon_index.png",
          selectedIconPath: "/images/icon_index_act.png",
          jumpType: "switchTab", // 跳转的类型
          tagNum: 0,
          text: "首页"
        }, {
          pagePath: "/pages/classificationII/classificationII",
          iconPath: "/images/icon_classify.png",
          selectedIconPath: "/images/icon_classify_act.png",
          jumpType: "switchTab",
          tagNum: 0,
          text: "分类"
        }, {
          pagePath: "/pages/shoppingCart/shoppingCart",
          iconPath: "/images/icon_cart.png",
          selectedIconPath: "/images/icon_cart_act.png",
          jumpType: "navigateTo",
          tagNum: 0,
          text: "购物车"
        }, {
          pagePath: "/pages/center2/center2",
          iconPath: "/images/icon_my.png",
          selectedIconPath: "/images/icon_my_act.png",
          jumpType: "switchTab",
          tagNum: 0,
          text: "我的"
        }]
      },
      /**
       * 组件的方法列表
       */
      methods: {
        switchTab(e) {
          const data = e.currentTarget.dataset
          const url = data.path
          const jumpType = data.jump_type;
          wx[jumpType]({
            url
          })
          this.setData({
            selected: data.index
          })
        },
      }
    })
    

    3、 /custom-tab-bar/index.wxss

    /* components/custom-tab-bar/index.wxss */
    /*      弹性盒居中            */
    .animated {
      -webkit-animation-duration: .7s;
      animation-duration: .7s;
      -webkit-animation-fill-mode: both;
      animation-fill-mode: both;
    }
    
    .animated.infinite {
      -webkit-animation-iteration-count: infinite;
      animation-iteration-count: infinite;
    }
    @keyframes bounceIn {
      from,  20%,  40%,  60%,  80%,
      to {
        -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
        animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
      }
      0% {
        opacity: 0;
        -webkit-transform: scale3d(0.3, 0.3, 0.3);
        transform: scale3d(0.3, 0.3, 0.3);
      }
      20% {
        -webkit-transform: scale3d(1.1, 1.1, 1.1);
        transform: scale3d(1.1, 1.1, 1.1);
      }
      40% {
        -webkit-transform: scale3d(0.9, 0.9, 0.9);
        transform: scale3d(0.9, 0.9, 0.9);
      }
      60% {
        opacity: 1;
        -webkit-transform: scale3d(1.03, 1.03, 1.03);
        transform: scale3d(1.03, 1.03, 1.03);
      }
      80% {
        -webkit-transform: scale3d(0.97, 0.97, 0.97);
        transform: scale3d(0.97, 0.97, 0.97);
      }
    
      to {
        opacity: 1;
        -webkit-transform: scale3d(1, 1, 1);
        transform: scale3d(1, 1, 1);
      }
    }
    
    .bounceIn {
      -webkit-animation-duration: 0.75s;
      animation-duration: 0.75s;
      -webkit-animation-name: bounceIn;
      animation-name: bounceIn;
      animation-delay: 0.26s;
    }
    
    .ak-flexC {
        display: -webkit-box;
        display: -moz-box;
        display: -ms-flexbox;
        display: -webkit-flex;
        display: flex;
        -webkit-justify-content: space-around;
        justify-content: space-around;
        -moz-box-pack: space-around;
        -webkit--moz-box-pack: space-around;
        box-pack: space-around;
        align-items: center;
        -webkit-align-items: center;
        box-align: center;
        -moz-box-align: center;
        -webkit-box-align: center;
    }
    
    /*      弹性盒居两边            */
    .ak-flexB {
        display: -webkit-box;
        display: -moz-box;
        display: -ms-flexbox;
        display: -webkit-flex;
        display: flex;
        -webkit-justify-content: space-between;
        justify-content: space-between;
        -moz-box-pack: space-between;
        -webkit--moz-box-pack: space-between;
        box-pack: space-between;
        align-items: center;
        -webkit-align-items: center;
        box-align: center;
        -moz-box-align: center;
        -webkit-box-align: center;
    }
    
    /* 				弹性盒纵向排列(居中) 			 */
    .ak-flex-columnC {
        display: -webkit-box;
        display: -moz-box;
        display: -ms-flexbox;
        display: -webkit-flex;
        display: flex;
        -webkit-justify-content: space-around;
        justify-content: space-around;
        -moz-box-pack: space-around;
        -webkit--moz-box-pack: space-around;
        box-pack: space-around;
        align-items: center;
        -webkit-align-items: center;
        box-align: center;
        -moz-box-align: center;
        -webkit-box-align: center;
        -webkit-box-orient: vertical;
        -webkit-box-direction: normal;
        -moz-box-orient: vertical;
        -moz-box-direction: normal;
        flex-direction: column;
        -webkit-flex-direction: column;
    }
    view{
      box-sizing: border-box;
    }
    .my-bar{
      position: fixed;
      bottom: 0;
      left: 0;
      z-index: 9;
      width: 100%;
      background-color: rgba(254, 254, 254, .96);
      box-shadow: 0 0 16px rgba(155, 155, 155, .5);
    }
    .my-bar__item{
      flex: 1;
      height: 98rpx;
      padding-top: 10rpx;
    }
    .my-bar__item-text{
      height: 100%;
      text-align: center;
      width: 100%;
      color: #333;
      position: relative;
    }
    .my-bar__item-text2:last-child{
      height: 100%;
      text-align: center;
      width: 100%;
      color: #333;
    }
    
    .my-bar__item-text, .my-bar__item-text2{
      font-size: 22rpx;
    }
    .my-bar__item-tag{
      position: absolute;
      top: 0;
      right: 62rpx;
      width: 26rpx;
      height: 26rpx;
      background-color: #d01716;
      color: #fff;
      border-radius: 50%;
      font-size: 20rpx;
    }
    .iconfont{
      font-size: 46rpx;
    }
    
    .my-bar__item-active{
      color: #d01716 !important;
    }
    
    
    .hackIPX{
      box-sizing: content-box;
      padding-bottom: 68rpx;
    }
    
    .my-bar__btn-img{
      width: 50rpx;
      height: 50rpx;
    }
    .my-bar__btn-img-act{
      width: 60rpx;
      height: 60rpx;
    }
    
    .hackIPX{
      box-sizing: content-box;
      padding-bottom: 48rpx;
      padding-top: 20rpx;
    }
    

    app.json

    
      "usingComponents": {
        "nav": "/components/nav_bar/nav_bar"
      },
      "tabBar": {
        "custom": true,
        "color": "#212121",
        "selectedColor": "#d01716",
        "backgroundColor": "#fefefe",
        "list": [
          {
            "pagePath": "pages/index/index",
            "iconPath": "/images/icon_index.png",
            "selectedIconPath": "/images/icon_index_act.png",
            "text": "首页"
          },
          {
            "pagePath": "pages/classificationII/classificationII",
            "iconPath": "/images/icon_classify.png",
            "selectedIconPath": "/images/icon_classify_act.png",
            "text": "分类"
          },
          {
            "pagePath": "pages/center2/center2",
            "iconPath": "/images/icon_my.png",
            "selectedIconPath": "/images/icon_my_act.png",
            "text": "我的"
          }
        ]
      },
    

    在用到tabBar的页面.js

      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
        let _this = this;
        if (!app.globalData.accessToken){
          // Tips: 1、没有有登录状态: 只设置tabbar
          console.log('没有有登录状态: 只设置tabbar')
          if (typeof this.getTabBar === 'function' &&
            this.getTabBar()) {
            this.getTabBar().setData({
              ['selected']: 0
            })
          }
        }else{
          // Tips: 2、有登录状态: 拿购物车 用户消息 优惠券数据
          console.log('有登录状态: 拿购物车 用户消息 优惠券数据')
          app.myRequest('cartNum', {}, 'get',
            function (res) {
              if (typeof _this.getTabBar === 'function' &&
                _this.getTabBar()) {
                _this.getTabBar().setData({
                  ['selected']: 0,
                  ['list[2].tagNum']: res.data
                })
              }
              _this.setData({
                cartNums: res.data
              })
            }, 'top');
          this.showCoupons();
        }
      },
    
    
    // 其实核心代码 其他的代码跟我的业务逻辑挂钩的
    //if (typeof this.getTabBar === 'function' &&
    //  this.getTabBar()) {
    //  this.getTabBar().setData({
    //    ['selected']: 0
    //  })
    //}
    

    OK 以上的这些玩意儿就够你玩转小程序的自定义tabBar了
    但是我们要考虑到有些用户死活不升级的情况
    (别问我为什么,在遍地都是iOS12.x 的时候,我的用户还有iOS8.x 的)
    就是微信版本低, 小程序的基础库版本也低,不支持展示小程序的自定义tabBar;
    此时如果我们不做兼容的话 用户将看不到底部栏

    适配低版本

    • 注意, 我们这里用的是自定义组件来代替小程序的自定义tabBar
      从项目结构上来说是用/components/tab_bar 来代替 /custom-tab-bar
      由于用到了自定义组件 而支自定义组件是从1.6.3 的基础版本开始支持的
      如果需要稳定的话, 推荐线上最低基础库需要支持到 2.1.0

    关键点有3个

    1. 自己的tabBar组件
    2. 隐藏官方的tabBar
    3. 控制自己的tabBar组建的显示和隐藏

    1. 自己的tanBar组件

    a. /components/tab_bar/tab_bar.js

    // components/table_bar/table_bar.js
    let app = getApp();
    Component({
      /**
       * 组件的属性列表
       */
      properties: {
        now: {
          type: String,
          value: 'index'
        },
        cartNum: {
          type: Number,
          value: 0,
        }
      },
    
      /**
       * 组件的初始数据
       */
      data: {
        isIpx: app.globalData.isIpx,
      },
      /**
       * 组件的方法列表
       */
      methods: {
        _tableJump: function(e) {
          let jumpType = e.currentTarget.dataset.jump;
          if (jumpType == this.properties.now) {
            return;
          } else {
            if (jumpType == 'index') {
              wx.switchTab({
                url: '/pages/index/index'
              })
            } else if (jumpType == 'my') {
              wx.switchTab({
                url: '/pages/center2/center2'
              })
            } else if (jumpType == 'classify') {
              wx.switchTab({
                url: '/pages/classificationII/classificationII'
              })
            } else if (jumpType == 'cart') {
              wx.navigateTo({
                url: '/pages/shoppingCart/shoppingCart'
              })
            } else {
              wx.reLaunch({
                url: '/pages/find/find'
              })
            }
          }
        },
      }
    })
    

    b. /components/tab_bar/tab_bar.wxml

    <!--components/tab_bar/tab_bar.wxml-->
    
    <view class='my-bar ak-flexB {{isIpx ? "hackIPX" : ""}}'>
      <view class='my-bar__item ak-flexC' bindtap='_tableJump' data-jump='index'>
        <view class='my-bar__item-text ak-flex-columnC {{now == "index" ? "my-bar__item-active" : ""}}'>
          <image src='/images/icon_index.png' class='my-bar__btn-img animated' mode='widthFix' hidden="{{now == 'index'}}"></image>
          <image src='/images/icon_index_act.png' class='my-bar__btn-img-act animated bounceIn' mode='widthFix' hidden="{{now != 'index'}}"></image>
          首页
        </view>
      </view>
    
      <view class='my-bar__item ak-flexC' bindtap='_tableJump' data-jump='classify'>
        <view class='my-bar__item-text ak-flex-columnC {{now == "classify" ? "my-bar__item-active" : ""}}'>
          <image src='/images/icon_classify.png' class='my-bar__btn-img animated' mode='widthFix' hidden="{{now == 'classify'}}"></image>
          <image src='/images/icon_classify_act.png' class='my-bar__btn-img-act animated bounceIn' mode='widthFix' hidden="{{now != 'classify'}}"></image>
          分类
        </view>
      </view>
    
      <view class='my-bar__item ak-flexC' bindtap='_tableJump' data-jump='cart'>
        <view class='my-bar__item-text ak-flex-columnC {{now == "cart" ? "my-bar__item-active" : ""}}'>
          <image src='/images/icon_cart.png' style='width: 56rpx; margin-top: -4rpx;' class='my-bar__btn-img animated' mode='widthFix' hidden="{{now == 'cart'}}"></image>
          <image src='/images/icon_cart_act.png' class='my-bar__btn-img-act animated bounceIn' mode='widthFix' hidden="{{now != 'cart'}}"></image>
          购物车
          <view hidden="{{cartNum <= 0}}" class='my-bar__item-tag ak-flexC'>{{cartNum}}</view>
        </view>
      </view>
    
      <view class='my-bar__item ak-flexC' bindtap='_tableJump' data-jump='my'>
        <view class='my-bar__item-text2 ak-flex-columnC {{now == "my" ? "my-bar__item-active" : ""}}'>
          <image src='/images/icon_my.png' class='my-bar__btn-img animated' mode='widthFix' hidden="{{now == 'my'}}"></image>
          <image src='/images/icon_my_act.png' class='my-bar__btn-img-act animated bounceIn' mode='widthFix' hidden="{{now != 'my'}}"></image>
          我的
        </view>
      </view>
    </view>
    

    c. 在使用的页面:

    pages/index/index.wxml
    <!-- pages/index/index.wxml -->
    <tab-bar wx:if="{{useMyTB}}" now="index" cart-num="{{cartNums}}"></tab-bar>
    
    
    pages/index/index.js :
    Page({
      data: {
        useMyTB: app.globalData.useMyTB,
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
        let _this = this;
        if (!app.globalData.accessToken){
          // Tips: 1、没有有登录状态: 只设置tabbar
          console.log('没有有登录状态: 只设置tabbar')
          if (typeof this.getTabBar === 'function' &&
            this.getTabBar()) {
            this.getTabBar().setData({
              ['selected']: 0
            })
          }
        }else{
          // Tips: 2、有登录状态: 拿购物车 用户消息 优惠券数据
          console.log('有登录状态: 拿购物车 用户消息 优惠券数据')
          
          app.myRequest('cartNum', {}, 'get',
            function (res) {
              if (typeof _this.getTabBar === 'function' &&
                _this.getTabBar()) {
                _this.getTabBar().setData({
                  ['selected']: 0,
                  ['list[2].tagNum']: res.data
                })
              }
              _this.setData({
                cartNums: res.data
              })
            }, 'top');
    
          app.myRequest('centerInfo', {},
            'get',
            function (res) {
              _this.setData({
                msg_num: res.data.msg_num,
                infoData: res.data,
                hiddenBindPhoneBlock: res.data.member.phone == '' ? false : true
              })
            }, 'top');
          this.showCoupons();
        }
      },
    

    2. 隐藏官方的tabBar

    首先我们要判断版本,如果低于2.5.0的话,
    做兼容, 隐藏官方的tabBar用自定义的tabBar;
    app.js的onLaunch中检查版本做适配

    // 做适配
        wx.getSystemInfo({
          success: function (res) {
            // 判断SDK版本
            let sdkv = res.SDKVersion;
            console.log('当前版本: ' + sdkv)
            let basicsVersion = [2, 5, 0]
            sdkv = sdkv.split(".");
            for (let i in sdkv) {
              if (parseInt(basicsVersion[i]) > parseInt(sdkv[i])) {
                console.warn('当前版本小于2.5.0')
                wx.hideTabBar();
                _this.globalData.useMyTB = true;
              }
            }
          },
        })
    

    3. 控制自己的tabBar组建的显示和隐藏

    其实上面代码有写啦 搜索 useMyTB

    以上这些就是我对小程序自定义tabBar的理解和应用了, 欢迎指点

    参考文档

    小程序官方的tabBar文档
    小程序官方的Component文档
    小程序app.json的配置

    展开全文
  • 主要介绍了微信小程序自定义tabbar custom-tab-bar 6s出不来解决方案,cover-view不兼容问题,需要的朋友可以参考下
  • 总结了三种在不使用微信小程序原生 tabbar 的情况下自制 tabbar 的方法。并说说这几种方法各自的特色。 类 navigator 跳转方式 类 navigator 跳转方式是我自己起的名称,因为它的实现思路就是这个样子的。期初...
  • 基于Vant Weapp 微信小程序自定义TabBar 根据微信小程序 官方文档 关于自定义TabBar的说明中进行操作。 步骤 1. app.json 添加关于 TabBar 的内容 "tabBar": { "custom": true, "list": [ { "pagePath": ...
  • 微信小程序原生的自定义tabBar组件,中间圆形凸起。支持darkMode,深色主题自适应 支持iPhoneX底部横线自适应

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,201
精华内容 1,680
关键字:

微信小程序自定义tabbar

微信小程序 订阅