值得记录的(五)- 微信小程序自定义 tabbar

一定的需求情况下,无法使用小程序原生的 tabbar 的时候,需要自行实现一个和 tabbar 功能一模一样的自制组件。

查阅了海量的博客和文档之后,亲自踩坑。总结了三种在不使用微信小程序原生 tabbar的情况下自制 tabbar 的方法。并说说这几种方法各自的特色。

类 navigator 跳转方式

类 navigator 跳转方式是我自己起的名称,因为它的实现思路就是这个样子的。期初参考 微信小程序自定义tabBar组件开发 这篇博文的思路。进行了这种方式的尝试,并为后续提供了解决思路。在这次实践的过程中使用了和该博文类似的目录结构。

template 文件主要包含了 tabbar 的内容、逻辑、模板、样式。

tabbar_template.js

//初始化数据
function tabbarinit() {
  return [
    {
      "current": 0,
      "pagePath": "/pages/travel_shop/travel/travel_index/travel_index",
      "iconPath": "/pages/img/[email protected]",
      "selectedIconPath": "/pages/img/[email protected]",
      "text": "首页"
    },
    {
      "current": 0,
      "pagePath": "/pages/travel_shop/travel/travel_car/travel_car",
      "iconPath": "/pages/img/[email protected]",
      "selectedIconPath": "/pages/img/[email protected]",
      "text": "购物车"
    },
    {
      "current": 0,
      "pagePath": "/pages/travel_shop/travel/travel_my/travel_my",
      "iconPath": "/pages/img/[email protected]",
      "selectedIconPath": "/pages/img/[email protected]",
      "text": "我的"
    }
  ]

}
//tabbar 主入口
function tabbarmain(bindName = "tabdata", id, target) {
  var that = target;
  var bindData = {};
  var otabbar = tabbarinit();
  otabbar[id][‘iconPath‘] = otabbar[id][‘selectedIconPath‘]   //换当前的icon
  otabbar[id][‘current‘] = 1;
  bindData[bindName] = otabbar
  that.setData({ bindData });
}

module.exports = {
  tabbar: tabbarmain
}

tabbar_template.wxml

<template name="tabBar">
  <view class="tabBar">
    <block wx:for="{{tabBar}}" wx:for-item="item" wx:key="tabBar">
        <view class="tabBar-item">
            <navigator open-type="reLaunch" url="{{item.pagePath}}">
                <view><image class="tabBar-icon" src=‘{{item.iconPath}}‘></image></view>
                <view class="{{item.current== 1 ? ‘tabBartext‘ :‘‘}}">{{item.text}}</view>
            </navigator>
        </view>
    </block>
 </view>
</template>

tabbar_template.wxss

.tabBar-icon{
  width:54rpx;
  height: 54rpx;
}
.tabBar{
  width:100%;
  position: fixed;
  bottom:0;
  padding:10rpx;
  margin-left:-4rpx;
  background:#F7F7FA;
  font-size:24rpx;
  color:#8A8A8A;
  box-shadow: 3rpx 3rpx 3rpx 3rpx #aaa;
  z-index: 9999;
}

 .tabBar-item{
  float:left;
  width: 33.333%;
  text-align: center;
  overflow: hidden;
}
/*当前字体颜色*/
.tabBartext{
  color: black;
}
.navigator-hover{
  background-color: rgba(0, 0, 0, 0);
}

而后在全局引入样式

@import "/pages/travel_shop/travel/tabbar_template/tabbar_template.wxss";

并在每一个页面的子文件(wxml、JS)中引入相应的内容

wxml 引入

<import src="/pages/travel_shop/travel/tabbar_template/tabbar_template.wxml"/>
<template is="tabBar" data="{{tabBar:bindData.tabBar}}"/>

JS 引入

var template = require("../tabbar_template/tabbar_template.js");

并在对应的 onLoad 生命周期中,注明它是哪一个 tabbar

  onLoad: function (options) {
    template.tabbar("tabBar", 1, this) //0表示第一个tabbar,这里1表示第二个 tabbar 的 icon
  },

效果预览

我们最终得到了效果,但这种效果带了明显的抖动闪烁。原因则是因为这种实现方式的本质是通过 navigator 和 JS 事件触发实现页面之间的跳转。因此我开始找寻另一种实现的方式。在 微信小程序自定义tabBar组件开发 这篇博客的留言板,我发现该文的作者也发现了这种方式的不足,并提到可以通过可以把页面都写成组件 component 的方式实现更好的效果。

template 模板 / component 组件

在继续查阅了一些关于小程序自定义 tabbar 的博客之后,找到了 微信小程序 - 自定义tabbar 这篇博文。按照这篇博文描述的结构,我也进行了尝试。发现这种方式不会出现之前跳转产生的那种闪烁现象出现。

之后再查阅 微信小程序 template 模板与 component 组件的区别和使用 这篇博文的时候了解到,如果当我们主要是为了展示页面的时候,可以使用 template 方式。如果涉及到 tabbar 对应各个页面的业务逻辑交互比较多,那就最好使用 component 组件。

因为这三个页面涉及到了很多独立的交互,所以我决定使用 component 组件的形式,将自定义的 tabbar 写成一个页面,然后将其他三个 tabbar 按钮对应的页面写成三个 component 组件。这种方法和 Vue 中的组件化很相似,可以把单个组件文件夹当成 Vue 中的一个 .vue 文件。

component 与普通 page 类似,但是 JS 文件和 JSON 文件与页面不同。

小程序组件 JS 模板

Component({
  /* 开启全局样式使用 */
  options: {
    addGlobalClass: true,
  },

  /* 组件的属性列表 */
  properties: {
    name: {
      type: String,
      value: ‘‘
    }
  },

  /* 组件的初始数据 */
  data: {

  },

  /* 生命周期函数 */
  lifetimes: {
    attached: function () { },
    moved: function () { },
    detached: function () { },
  },

  /* 组件的方法列表 */
  methods: {

  },
})

component 组件 JSON 文件

{
  "component": true,
  "usingComponents": {}
}

tabbar 引用和配置

引用组件 JSON

按照如图的结构,三个 component 作为子组件,tabber 作为一个父级,因此它的 JSON 需要引入这三个 component 组件。

// travel.json
{
  "usingComponents": {
    "travel_car": "travel_car/travel_car",
    "travel_index": "travel_index/travel_index",
    "travel_my": "travel_my/travel_my"
  }
}

tabbar JS

而该页面的 JS 仅仅只用来控制 tabbar 的 icon 选择,和传递一个 index 告诉页面该隐藏和显示哪一个 component 组件。

// travel.js
let app = getApp()

Page({
  data: {
    currentTab: 0,
    items: [
      {
        "iconPath": "/pages/img/[email protected]",
        "selectedIconPath": "/pages/img/[email protected]",
        "text": "首页"
      },
      {
        "iconPath": "/pages/img/[email protected]",
        "selectedIconPath": "/pages/img/[email protected]",
        "text": "购物车"
      },
      {
        "iconPath": "/pages/img/[email protected]",
        "selectedIconPath": "/pages/img/[email protected]",
        "text": "我的"
      }
    ]
  },
  //事件处理函数
  bindChange: function (e) {
    let that = this;
    that.setData({
      currentTab: e.detail.current
    });
  },
  swichNav: function (e) {
    let that = this;
    if (this.data.currentTab === e.target.dataset.current) {
      return false;
    } else {
      that.setData({
        currentTab: e.target.dataset.current
      })
    }
  },
  onLoad: function () {
    let that = this
    app.getUserInfo(function (userInfo) {
      that.setData({
        userInfo: userInfo
      })
    })
  }
})

tabbar WXML

直接使用之前 JSON 中引用过的标签名,类似于 Vue 中使用模板标签。这里由于组件模板标签不支持直接使用 hidden 属性,所以在外包裹了一层 view 标签用来添加 hidden属性。

<view hidden="{{currentTab == 0? false: true}}">
  <travel_index/>
</view>
<view hidden="{{currentTab == 1? false: true}}">
  <travel_car/>
</view>
<view hidden="{{currentTab == 2? false: true}}">
  <travel_my/>
</view>

<view class="nav-tabs">
  <view class="tab-list {{currentTab == idx ? ‘active‘ : ‘default‘ }}" wx:for="{{items}}" wx:key="prototype" wx:for-index="idx" wx:for-item="item" data-current="{{idx}}" bindtap="swichNav">
    <text class="tab-text" wx:for-index="idx" data-current="{{idx}}" src="{{currentTab == idx ? item.selectedIconPath : item.iconPath }}">{{item.text}}</text>
    <image class="iconPath" wx:for-index="idx" data-current="{{idx}}" src="{{currentTab == idx ? item.selectedIconPath : item.iconPath }}"></image>
  </view>
</view>

tabbar WXSS

Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors.(./pages/xxx/xxx.wxss:288:3)This wxss file is ignored.

造成这种报错的原因是 component 组件的样式中不能包含一些特定的选择器。

page {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.nav-tabs {
  width: 100%;
  display: flex;
  position: fixed;
  bottom: 0;
}

.tab-list {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column-reverse;
  background: #fcfcfc;
}

.tab-text {
  font-size: 24rpx;
  line-height: 35rpx;
  color: #5f5f5f;
}

.iconPath {
  width:54rpx;
  height: 54rpx;
}

.tab-content {
  flex: 1;
}

.default {
  line-height: 75rpx;
  text-align: center;
  flex: 1;
  color: #eee;
  font-weight: bold;
  font-size: 28rpx;
}

.active {
  line-height: 75rpx;
  text-align: center;
  color: black;
  flex: 1;
  font-weight: bold;
  font-size: 28rpx;
}

.show {
  display: block;
  flex: 1;
}

.hidden {
  display: none;
  flex: 1;
}

预览效果

最终就完成了一个非原生小程序 tabbar 的自定义 tabbar 。

Github

在这篇文章发布之后,有一些朋友询问。 我重新整理了一个比较清晰整洁的 Demo 发布在了 GitHub
如果这个 Demo 能够帮助到您。请不要吝惜您的 Star??。

Demo地址:https://github.com/evenyao/wx-diy-tabbar

参考

微信小程序自定义tabBar组件开发
微信小程序 - 自定义tabbar
微信小程序 template 模板与 component 组件的区别和使用

原文地址:https://www.cnblogs.com/evenyao/p/10001970.html

时间: 2024-10-20 14:20:26

值得记录的(五)- 微信小程序自定义 tabbar的相关文章

微信小程序自定义tabbar的问题

个人感觉小程序的tab样式自定义的能力有所欠缺,不够美观,于是今天自己diy了一个tab 测试的时候发现,无论是使用navigator跳转(会出现点击的效果)还是用bindtap(触摸),因为没有定义tabbar, 跳转的方式都只能是页面重定向的,导致tab页上的ABCD互相跳转的时候,每次都会重新渲染视图,由此带来的 视觉效果很不好,没有系统tabbar跳转地自然,万般无奈之下,只好用回系统自带的tabbar. 如果你有好的方法能够解决自定义tabbar跳转重新渲染的问题,烦请告知,在此谢过!

微信小程序自定义tabBar和遇到的一些问题

第一步 在app.json文件找到“tarBar”对象,然后添加一个属性,代码如下: "tabBar": { "custom": true, //添加这个属性 "color": "#707070", "selectedColor": "#00c4cc", "list": [ { "pagePath": "pages/home/index&

微信小程序 - 自定义tabbar

各种奇葩的需求,造就了我们 wxml 1 <view class="nav-tabs"> 2 <view class="tab-list {{currentTab == idx?'active':'default'}}" wx:for="{{tabArray}}" wx:key="prototype" wx:for-index="idx" wx:for-item="itemNam

微信小程序-自定义底部导航

代码地址如下:http://www.demodashi.com/demo/14258.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html 1.基本需求. 实现用户自定义底部导航 2.案例目录结构 二.程序实现具体步骤 1.自定义nav.wxml代码 <template name="nav"> <view class=&quo

记录如何发布微信小程序npm包

1.初始化项目 在项目根目录下使用一下命令 npm init 这时终端会提示你输入诸如包名,版本号等信息,如下: 2.新建src文件夹 新建src文件夹之后,把微信小程序自定义组件的index.js.index.wxss.index.json.index.wxml四个文件都拉到src文件夹里面即可.文件目录如下图: 3.修改package.json文件 在 package.json 文件中新增一个 miniprogram 字段,指向src文件即可.这是官方文档发布npm的约束条件.npm支持 微

微信小程序自定义弹窗wcPop插件|仿微信弹窗样式

微信小程序自定义组件弹窗wcPop|小程序消息提示框|toast自定义模板弹窗 平时在开发小程序的时候,弹窗应用场景还是蛮广泛的,但是微信官方提供的弹窗比较有局限性,不能自定义修改.这个时候首先想到的是自定义组件化开发,就是把弹出框封装成一个组件,然后多处调用. 解决了小程序开发自定义弹窗出现后,遮罩层下的页面仍可以滚动的方法: 给遮罩层的最外层view中加入catchtouchmove="preventTouchMove" 即可解决该遮罩层点透问题. 根据需要还可以自定义多个按钮及事

微信小程序自定义导航栏(wx_custom_navigation_bar) 自定义返回键、首页键,动态设置标题,响应式组件

微信小程序自定义导航栏 navigation bar 返回键 首页 github: https://github.com/chen-yt/wx_custom_navigation_bar https://github.com/Superman2113/wx_custom_navigation_bar 代码 navbar组件 navbar.wxml <view class="navbar" style="{{'height: ' + navigationBarHeight

微信小程序-自定义QQ版下拉刷新

最近给别个公司做技术支持,要实现微信小程序上拉刷新与下拉加载更多 微信给出的接口不怎么友好,最终想实现效果类似QQ手机版 ,一共3种下拉刷新状态变化,文字+图片+背景颜色 最终实现后的效果(这里提示有个不同点就是,自定义了导航条,并且下拉的时候,自定义导航条必须固定) 小程序实现下拉加载2种方式: 1. 简单粗暴,直接开启enablePullDownRefresh,开启全局下拉刷新 2.利用scroll-view组件 简单分析下2种方式的利与弊 enablePullDownRefresh方式 优

微信小程序 自定义标题栏

微信小程序可以设置自定义标题栏,可以针对不同页面单独设置1. 在页面文件 .json 文件中,设置如下属性,自定义导航栏 和 导航栏样式"navigationStyle": "custom","navigationBarTextStyle": "white", 特别是第二个 navigationBarTextStyle 属性 可以将胶囊样式调整为透明效果 2. 设置自定义导航栏布局 样式 动效逻辑等 3. 划重点!!!导航栏中