相信很多小伙伴在开发微信小程序的时候都会有自定义顶部导航栏的需求,不够要说明的是小程序右上角的胶囊是不能自定义的哦,除了胶囊其他地方都是可以根据自己的项目而定了,在一次小程序开发中就需要对顶部进行自定义在此记录一下自己封装这个组件的过程。
组件编写
既然今天需要把导航栏封装为组件那么就需要以下几个步骤:
组件结构搭建
首先搭建一个如下图的结构:
组件基础代码编写
此时我们就需要根据官方文档查看得知如果要定制必须在配置文件中修改默认的配置文件,其实这里可以针对某个页面page进行设置,以index为例在index.json文件中配置如下代码即可看到如下效果:
结构
view class='topbar' view class='status' style="height:{{statusHeight}}px"/view view class='navbar' style="height:{{navHeight}}px" view class='navbar_back' bindtap='backClick' image src='../images/black_back.png'/image /view view class='navbar_title' style="height:{{navHeight}}px" view标题/view /view /view/view复制代码这里的主要思路就是用fixed定位,后面会有内容顶到底部的布局,所以全部用定位会方便些,整体就两个部分一个是状态栏一个就是标题和按钮的部分了。
样式
.topbar { position: fixed; left: 0; top: 0; width: 100%; z-index: 9999;}.status { width: 100%;}.navbar { width: 100%; display: flex; justify-content: flex-start; align-items: center; position: relative;}.navbar_back { padding: 0 32rpx; display: flex; justify-content: flex-start; align-items: center; height: 100%;}.navbar_back image { width: 21rpx; height: 34rpx;}.navbar_title { position: absolute; left: 0; top: 0; width: 100%; text-align: center; display: flex; justify-content: center; align-items: center; z-index: -1;}.navbar_title view { width: 40%; word-break: break-all; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 38rpx;}复制代码样式中没有太多的东西,唯一需要说的就是大部分模块都是定位做的,唯一没考虑好的就是标题太长不好处理,这里用了简单粗暴的方法给设定一个宽度。
逻辑处理
Component({ properties: { /** * 自定义返回事件处理 * customBackReturn="{{true}}" bind:customBackReturn="customBackReturn" */ customBackReturn: { type: Boolean, value: false } }, data: { }, methods: { backClick() { if (this.data.customBackReturn) { this.triggerEvent("customBackReturn") } else { if (getCurrentPages().length == 1) { wx.switchTab({ url: '/pages/index/index', }) } else { wx.navigateBack({ delta: 1 }) } } } }, attached() { var self = this; wx.getSystemInfo({ success(res) { var isIos = res.system.indexOf('iOS') -1; self.setData({ statusHeight: res.statusBarHeight, navHeight: isIos ? 44 : 48 }) } }) }})复制代码逻辑中主要在两个地方一个是获取系统信息时对于导航高度的判断,另外一个是返回上一页的逻辑,默认就是打开首页(注意用的api),如果有自定义事件就用自定义事件customBackReturn
效果
目前效果就和没有自定义之前差不多就是一个普通的返回按钮和标题文字,如下图:
带返回按钮的导航
小程序中特别是分享出去的页面,如果没有一个返回主页的按钮,用户更本不知道怎么回到小程序的主页,所以给用户带来了很大的不便,因此这样的需求就必须要有了,如果实现呢?其实很简单,毕竟已经出来一个了,需要的就是加一个上去就行了。
结构
view class='topbar' view class='status' style="height:{{statusHeight}}px"/view view class='navbar' style="height:{{navHeight}}px" view class='navbar_home' image src='../images/black_back.png' bindtap='backClick'/image image src='../images/home_black.png' bindtap='homeClick'/image /view !-- view class='navbar_back' bindtap='backClick' image src='../images/black_back.png'/image /view -- view class='navbar_title' style="height:{{navHeight}}px" view标题/view /view /view/view复制代码大家注意到我把之前的代码注释了而不是直接在前面的代码上修改,其实这里留着是为了后面可以自定义想要那种导航形式。
样式
.navbar_home { margin-left: 32rpx; display: flex; justify-content: flex-start; align-items: center; border-radius: 33rpx; border: 1px solid rgba(0, 0, 0, 0.1); background: rgba(0,0,0,0.2); box-sizing: border-box; padding: 10rpx 0;}.navbar_home image:first-child { width: 21rpx; height: 34rpx; padding: 0 32rpx; border-right: 1px solid rgba(255,255,255,0.2);}.navbar_home image:last-child { width: 37rpx; height: 35rpx; padding: 0 32rpx;}复制代码同样的样式也只是在之前的基础上增加了上面这些样式。
逻辑
homeClick() { wx.switchTab({ url: '/pages/index/index', }) }复制代码逻辑也只是在methods中添加一个返回主页的事件而已,这里需要大家根据自己的项目情况而定。
效果
样式大家可以根据自己项目而定。
到这两部分的功能都完成了,但是如果现在我们在首页中添加一些内容你就会发现问题了,如下:
view style="height:{{statusHeight+navHeight}}px" hidden='{{false}}'/viewview class='topbar' view class='status' style="height:{{statusHeight}}px"/view view class='navbar' style="height:{{navHeight}}px" view class='navbar_home' image src='../images/black_back.png' bindtap='backClick'/image image src='../images/home_black.png' bindtap='homeClick'/image /view !-- view class='navbar_back' bindtap='backClick' image src='../images/black_back.png'/image /view -- view class='navbar_title' style="height:{{navHeight}}px" view标题/view /view /view/view复制代码效果如下:
封装导航栏使其可定制化
为了能使使用更加方便,需要对上面的导航栏进行进一步封装以适应不同需求。
结构改造
首先需要改造的就是结构,让更多的选项能够进行配置,结构改造如下:
view style="height:{{statusHeight+navHeight}}px" hidden='{{header.hiddenBlock}}'/viewview class='topbar' style="background:{{header.headerbg}}" view class='status' style="height:{{statusHeight}}px"/view view class='navbar' style="height:{{navHeight}}px" block wx:if="{{header.slot}}" slot/slot /block block wx:else view class='navbar_home' wx:if="{{header.homeCapsule}}" style="background:{{header.capsulebg}};border:{{header.capsuleborder}}" image src='../images/black_back.png' bindtap='backClick' style="border-right:{{header.capsulesep}}"/image image src='../images/home_black.png' bindtap='homeClick'/image /view view class='navbar_back' bindtap='backClick' wx:else image src='../images/black_back.png'/image /view view class='navbar_title' style="height:{{navHeight}}px" view style="color:{{header.fontColor}};font-size:{{header.fontSize}}"{{header.title}}/view /view /block /view/view复制代码上面所有的参数都是可以配置的,这就大大的给了开发者定制不同风格了,如果还是有不符合的建议你直接修改上面的代码或者自己封装一个更好。
逻辑改造
Component({ properties: { header: { type: Object, value: { homeCapsule: false, headerbg: "#fff", title: "", fontColor: "#000", fontSize: '16', hiddenBlock: false, capsulebg: 'rgba(0,0,0,0.2)', capsuleborder: '1px solid rgba(0, 0, 0, 0.1)', capsulesep: '1px solid rgba(255,255,255,0.2)', slot: false } }, /** * 自定义返回事件处理 * customBackReturn="{{true}}" bind:customBackReturn="customBackReturn" */ customBackReturn: { type: Boolean, value: false } }, methods: { backClick() { if (this.data.customBackReturn) { this.triggerEvent("customBackReturn") } else { if (getCurrentPages().length == 1) { wx.switchTab({ url: '/pages/index/index', }) } else { wx.navigateBack({ delta: 1 }) } } }, homeClick() { wx.switchTab({ url: '/pages/index/index', }) } }, attached() { var self = this; wx.getSystemInfo({ success(res) { var isIos = res.system.indexOf('iOS') -1; self.setData({ statusHeight: res.statusBarHeight, navHeight: isIos ? 44 : 48 }) } }) }})复制代码结构的改造其实就是添加一些能够传入的值来定制化。
到这里基本上这个组件就封装好了,接下来就是使用这个组件了。
常规带有一个返回按钮的案例
这种方式的应用很简单直接配置一些参数即可。
先引入组件如下:
{ "navigationStyle":"custom", "usingComponents": { "header":"../../components/navbar/navbar" }}复制代码需要配置导航栏自定义,不然就没有效果,根据自己的路径引入即可,如果所有页面都需要用到,建议直接在app.json中配置,这样就不用每个页面去配置了。
wxml中使用组件标签
header header='{{header}}'/headerview内容区域哦/view复制代码在需要用到的页面使用header标签即可
js文件中配置参数
Page({ data: { header:{ homeCapsule: false, title: '标题', fontColor: "#000", fontSize: '36rpx', headerbg: '#f40', hiddenBlock: false, slot: false } }, onLoad: function() {}});复制代码这里有三个参数是必须要配置的:homeCapsule,hiddenBlock,slot三个参数分别代表的含义是是否显示带有home按钮的,是否隐藏整个顶部(后面会介绍),是否需要自定义结构
效果
内容置顶的实例
有时候需要将内容置顶,看起来会比较好看,所以就需要对hiddenBlock进行配置了,看代码:
header header='{{header}}'/headerimage src='../../images/timg.jpg' style="width:100%" mode="aspectFill"/imageview内容区域哦/view复制代码重要的是如何配置,如下:
Page({ data: { header:{ homeCapsule: false, title: '', headerbg: 'transparent', hiddenBlock: true, slot: false } }, onLoad: function() {}});复制代码效果如下:
带有home按钮的导航
分享页需要带有返回首页的按钮,如何配置呢?有了这个组件就很容易配置了,配置如下:
Page({ data: { header:{ homeCapsule: true, title: '测试标题', headerbg: '#f40', hiddenBlock: false, slot: false } }, onLoad: function() {}});复制代码效果如下:
完全自定义
如果以上都不能满足需求,那么只有自己写了,简单实例如下:
header header='{{header}}' view测试的标题哦/view/headerimage src='../../images/timg.jpg' style="width:100%" mode="aspectFill"/imageview内容区域哦/view复制代码配置如下:
Page({ data: { header:{ headerbg: 'transparent', hiddenBlock: false, slot: true } }, onLoad: function() {}});复制代码效果如下:













