当前位置:   article > 正文

微信小程序自定义 tab-bar(基于 wepy)_wepy实现custom-tab-bar

wepy实现custom-tab-bar

背景

微信小程序提供的原生 tab-bar 功能简单,样式单一,无法满足业务需求。
项目中使用的是 wepy 1.x 框架,实现原理与原生类似。

方案

一、 使用组件,在每个Tab页引入

  1. 修改全局配置

    // app.wpy
    export default class extends wepy.app {
        config = {
          tabBar: {
                custom: true,
                // ...
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  2. 编写 tab-bar 组件

    <!-- CustomTabBar.wpy -->
    <template>
        <cover-view class="tab-bar">
            <cover-view class="tab-bar-border"></cover-view>
            <cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
                <cover-image class="icon" src="{{selected == index ? item.selectedIconPath : item.iconPath}}"></cover-image>
                <cover-view style="color: {{selected == index ? selectedColor : color}}">{{item.text}}</cover-view>
            </cover-view>
        </cover-view>
    </template>
    
    <script>
    import wepy from 'wepy';
    
    export default class CustomTabBar extends wepy.component {
        props = {
            selected: {
                type: String,
                default: '0'
            }
        }
    
        data = {
            color: '#7A7E83',
            selectedColor: '#6280f5',
            list: [
                {
                    selectedIconPath: '../images/tab_application_pre.png',
                    iconPath: '../images/tab_application.png',
                    pagePath: '/pages/Application',
                    text: '应用'
                },
                {
                    selectedIconPath: '../images/tab_project_pre.png',
                    iconPath: '../images/tab_project.png',
                    pagePath: '/pages/Machines',
                    text: '机械'
                },
                {
                    selectedIconPath: '../images/tab_message_pre.png',
                    iconPath: '../images/tab_message.png',
                    pagePath: '/pages/Message',
                    text: '消息'
                },
                {
                    selectedIconPath: '../images/tab_mine_pre.png',
                    iconPath: '../images/tab_mine.png',
                    pagePath: '/pages/MyHome',
                    text: '我的'
                }
            ]
        }
        methods = {
            switchTab(e) {
                const data = e.currentTarget.dataset;
                const url = data.path;
                wx.switchTab({ url });
            }
        }
    }
    </script>
    <style lang='less' scoped>
    .tab-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: 160rpx;
        background: white;
        display: flex;
        padding-top: 8rpx;
        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;
    
            cover-image {
                width: 27px;
                height: 27px;
                margin-bottom: 12rpx;
            }
    
            cover-view {
                font-size: 10px;
            }
        }
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  3. 在所有 tab 页引用

    <!-- Application.wpy -->
    <template>
    	<view>
      	<CustomTabBar selected="0" />
      </view>
    </template>
    
    <script>
    import CustomTabBar from '../components/CustomTabBar';
     
    export default class Application extends wepy.page {
    	components = {
        CustomTabBar
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

二、 官方推荐方式

  1. 在根目录创建 custom-tab-bar 文件夹,创建 index.wpy 文件。

    实际上,根据官方文档指引,应该在 custom-tab-bar 目录下创建 .js.wxml.wxss.json 文件。由于项目小程序使用 wepy 框架,所以创建的是 .wpy 文件,编译后会生成相应的文件。

    <!-- index.wpy -->
    <template>
        <cover-view class="tab-bar">
            <cover-view class="border"></cover-view>
            <cover-view wx:for="{{list}}" wx:key="index" class="item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
                <cover-view wx:if="{{badge[index]}}" class="badge">{{badge[index]}}</cover-view>
                <cover-image src="{{selected === index ? item.selectedIconPath : item.iconPath}}" />
                <cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
            </cover-view>
        </cover-view>
    </template>
    
    <script>
    // 此处使用的是原生创建组件的方式,保证编译后符合官方推荐的格式。
    Component({
        data: {
            badge: {},
            selected: 0,
            color: '#7A7E83',
            selectedColor: '#6280f5',
            list: [
                {
                    selectedIconPath: '../images/tab_application_pre.png',
                    iconPath: '../images/tab_application.png',
                    pagePath: '/pages/Application',
                    text: '应用'
                },
                {
                    selectedIconPath: '../images/tab_news_pre.png',
                    iconPath: '../images/tab_news.png',
                    pagePath: '/pages/News',
                    text: '新闻'
                },
                {
                    selectedIconPath: '../images/tab_message_pre.png',
                    iconPath: '../images/tab_message.png',
                    pagePath: '/pages/Message',
                    text: '消息'
                },
                {
                    selectedIconPath: '../images/tab_mine_pre.png',
                    iconPath: '../images/tab_mine.png',
                    pagePath: '/pages/MyHome',
                    text: '我的'
                }
            ]
        },
        attached () {
        },
        methods: {
            switchTab (e) {
                const data = e.currentTarget.dataset
                const url = data.path
                wx.switchTab({ url })
                this.setData({
                    selected: data.index
                });
            },
            setTabBarBadge(options) {
                if (!options) return;
                const { index, text } = options
                const badge = this.data.badge || {};
                badge[index] = text;
                this.setData({
                    badge
                });
            },
            removeTabBarBadge(options) {
                if (!options || options.index === undefined) return;
                const { index } = options;
                const badge = this.data.badge || {};
                badge[index] = null;
                this.setData({
                    badge
                });
            }
        },
    })
    
    // NOTE: 此处导出含 config 属性的类,是为了保证编译后生成 .json 文件
    export default class CustomTabBar {
        config = {
            component: true
        }
    }
    </script>
    <style lang='less' scoped>
    .tab-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        background: white;
        display: flex;
        padding-top: 16rpx;
        padding-bottom: env(safe-area-inset-bottom);
        .border {
            background-color: rgba(0, 0, 0, 0.33);
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 1px;
            transform: scaleY(0.5);
        }
        .item {
            position: relative;
            flex: 1;
            text-align: center;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            .badge {
                position: absolute;
                top: 0;
                right: 50%;
                padding: 4rpx 12rpx;
                border-radius: 28rpx;
                font-size: 20rpx;
                background-color: red;
                color: #fff;
                z-index: 3;
                transform: translateX(100%);
            }
            cover-image {
                width: 27px;
                height: 27px;
                margin-bottom: 12rpx;
            }
            cover-view {
                font-size: 10px;
            }
        }
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
  2. 同方案一的步骤一,修改全局配置。

  3. 在每个 tab 页中设置 tabBar 的选中状态。

    <!-- Application.wpy -->
    export default class Application extends wepy.page {
     	onShow() {
        if (this.$wxpage && typeof this.$wxpage.getTabBar === 'function') {
            const tabBar = this.$wxpage.getTabBar();
          	tabBar.setData({
              selected: 0, // 由于Application是第一个tab页
            });
        }
      } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  4. 封装常用操作 tabBar 的方法,包括 tabBar 徽标功能。

    // 获取自定义 tabBar 组件示例
    export const getCustomTabBar = ctx => {
        let tabBar = null;
        if (ctx && ctx.$wxpage && typeof ctx.$wxpage.getTabBar === 'function') {
            tabBar = ctx.$wxpage.getTabBar();
        }
        return tabBar;
    };
    
    // 设置 active tabBar
    export const setActiveTabBar = (ctx, index = 0) => {
        const tabBar = getCustomTabBar(ctx);
        if (tabBar) {
            tabBar.setData({
                selected: index
            });
        }
    };
    
    // 设置徽标
    export const setTabBarBadge = (ctx, options = { index: 0, text: '' }) => {
        const { index = 0, text = '' } = options;
        const tabBar = getCustomTabBar(ctx);
        if (tabBar) {
            tabBar.setTabBarBadge({
                index,
                text
            });
        } else {
            wx.setTabBarBadge({
                index,
                text
            });
        }
    };
    
    // 移除徽标
    export const removeTabBarBadge = (ctx, options = { index: 0 }) => {
        const { index = 0 } = options;
        const tabBar = getCustomTabBar(ctx);
        if (tabBar) {
            tabBar.removeTabBarBadge({
                index
            });
        } else {
            wx.removeTabBarBadge({
                index
            });
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

注意

在自定义 tabBar 模式下

  • 为了保证低版本兼容以及区分哪些页面是 tab 页,tabBar 的相关配置项仍然需要完整声明,但这些字段不会作用于自定义 tabBar 的渲染。
  • 此时需要开发者提供一个自定义组件来渲染 tabBar,所有 tabBar 的样式都由该自定义组件渲染。推荐用 fixed 在底部的 cover-view + cover-image 组件渲染样式,以保证 tabBar 层级相对较高。
  • 与 tabBar 样式相关的接口,如 wx.setTabBarItem 等将失效。
  • 每个 tab 页下的自定义 tabBar 组件实例是不同的,可通过自定义组件下的 getTabBar 接口,获取当前页面的自定义 tabBar 组件实例。

注意

如需实现 tab 选中态,要在当前页面下,通过 getTabBar 接口获取组件实例,并调用 setData 更新选中态。

参考

  1. 微信小程序开发文档
  2. wepy github issue#2052
  3. https://www.yuque.com/currywxj/pwgsgm/mci8h7#ZSOWI
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/117110
推荐阅读
相关标签
  

闽ICP备14008679号