小程序实现自定义导航栏适配完美版


Posted in Javascript onApril 02, 2019

1、发现问题

小程序页面自定义导航栏功能已经开放有些日子了(还不知道这个功能的可以先>>了解一下),这极大的提升了小程序开发的自由度,相信不少小伙伴已经使用过这个功能,同时也相信不少小伙伴在此功能开发过程中踩过同样的一些坑:

  • 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一;
  • 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮;
  • 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂。

同样的,这些问题也是小灰经历过的。但是小灰相信,办法总比问题多,于是开始了自己的探究:

2、一探究竟

为了搞明白到底该怎么去适配,老规矩,我先翻了一波官方文档,还别说,官方还真有这么一段介绍了相关细节,>>详情点击:

小程序实现自定义导航栏适配完美版

从图中分析,我们可以得到如下信息:

  • Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt
  • 胶囊按钮高度为32pt, iOS和Android一致

这。。。,好像并没有什么L用啊??这仅仅是普通屏幕为参照的,ipx, 安卓全面屏完全没介绍。
沉着冷静,我们接着分析:

  • 胶囊按钮到状态栏下边缘这块距离,好像是固定的?
  • 安卓这个图,好像有点奇怪?导航栏分为 状态栏+标题栏?
  • 如果车两个条件成立,那我们的问题是不是就解决了80%了?

那么我们来论证一下:

第一个问题:胶囊按钮到状态栏下边缘的距离是不是固定的?

很简单,我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度

为了好测量,我们设置状态栏背景色为深色

js代码:

var sysinfo = wx.getSystemInfoSync();
this.setData({ 
 statusBarHeight:sysinfo.statusBarHeight 
})

wxml代码:

<view class="status-bar" style="height:{{statusBarHeight}}px"></view>

wxss代码:

.status-bar{
 background: rgb(141, 71, 71);
 }

效果图(iPhone6):

小程序实现自定义导航栏适配完美版

效果图(iPhoneX):

小程序实现自定义导航栏适配完美版

效果图(安卓):

小程序实现自定义导航栏适配完美版

是不是有点眉目了?是的,从截图可以看出,iOS是一致的,但是Android好像有所差别。

那究竟距离是多少?我们用神器(微信截图)来量一量:

Android:

小程序实现自定义导航栏适配完美版

iOS:

小程序实现自定义导航栏适配完美版

可以看出,iOS胶囊按钮与状态栏之间距离为:6px, Android为8px,并且经过测量,iOS各机型,Android各机型结果一致(由于篇幅原因,就不一一展示截图了,有兴趣的可以自行测量)

第二个问题:导航栏分为 状态栏+标题栏?

通过对第一个问题的论证,很明显能看出来确实是这样的。并且通过第一个问题的测量结果以及官方提供的数据,我们可以对标题栏高度进行计算:

  • 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2
  • Android导航栏高度 = 32px + 8px * 2 = 48px
  • iOS导航栏高度 = 32px + 6px * 2 = 44px

*注:由于胶囊按钮是原生组件,为表现一直,其单位在个系统都为px,所以我们的自定义导航栏各个高度的单位都必需是px(切记不能用rpx),才能完美适配。

3、解决问题

通过上述分析,相信小伙伴们都能有一个解决问题的思路了,在上代码之前,小灰再给大家画一下重点:

  • 写自定义导航组件的时候,需要将组件结构一分为二:状态栏 + 标题栏
  • 状态栏高度可通过wx.getSystemInfoSync().statusBarHeight获取
  • 标题栏高度:安卓:48px,iOS:44px
  • 单位必需跟胶囊按钮一致,用px

话不多说,上代码(gitHub地址):
js:

Component({ 
 properties: { 
 background: {  
 type: String,  
 value: 'rgba(255, 255, 255, 1)' 
 }, 
 color: {  
 type: String,  
 value: 'rgba(0, 0, 0, 1)' 
 }, 
 titleText: {  
 type: String,  
 value: '导航栏' 
 }, 
 titleImg: {  
 type: String,  
 value: '' 
 }, 
 backIcon: {  
 type: String,  
 value: '' 
 }, 
 homeIcon: {  
 type: String,  
 value: '' 
 }, 
 fontSize: {  
 type: Number,  
 value: 16 
 }, 
 iconHeight: {  
 type: Number,  
 value: 19 
 }, 
 iconWidth: {  
 type:Number,  
 value: 58 
 } 
 }, 
attached: function(){ 
 var that = this; 
 that.setNavSize(); 
 that.setStyle(); 
}, 
 data: {
 }, 
methods: { 
// 通过获取系统信息计算导航栏高度 
setNavSize: function() {  
var that = this  
 , sysinfo = wx.getSystemInfoSync()  
 , statusHeight = sysinfo.statusBarHeight  
 , isiOS = sysinfo.system.indexOf('iOS') > -1  
 , navHeight;  
if (!isiOS) {  
 navHeight = 48;  
 } else {  
 navHeight = 44;  
}  
that.setData({  
 status: statusHeight,  
 navHeight: navHeight  
 }) 
}, 
setStyle: function() {  
 var that = this  
 , containerStyle  
 , textStyle  
 , iconStyle;  
 containerStyle = [  
 'background:' + that.data.background  
 ].join(';');  
 textStyle = [  
 'color:' + that.data.color,  
 'font-size:' + that.data.fontSize + 'px'  
 ].join(';');  
 iconStyle = [  
 'width: ' + that.data.iconWidth + 'px',  
 'height: ' + that.data.iconHeight + 'px'  
 ].join(';');  
 that.setData({  
  containerStyle: containerStyle,  
  textStyle: textStyle,  
  iconStyle: iconStyle  
 }) }, 
 // 返回事件 
back: function(){  
 wx.navigateBack({  
 delta: 1  
 })  
 this.triggerEvent('back', {back: 1}) 
}, 
home: function() {  
 this.triggerEvent('home', {}); 
 } 
 }})

wxml:

<view class='nav' style='height: {{status + navHeight}}px'> 
 <view class='status' style='height: {{status}}px;{{containerStyle}}'></view>    <view class='navbar' style='height:{{navHeight}}px;{{containerStyle}}'> <view class='back-icon' wx:if="{{backIcon}}" bindtap='back'>   <image src='{{backIcon}}'></image> 
  </view> 
 <view class='home-icon' wx:if="{{homeIcon}}" bindtap='home'>  
 <image src='{{homeIcon}}'></image> 
 </view> [链接描述][10]
 <view class='nav-icon' wx:if="{{titleImg}}">  
 <image src='{{titleImg}}' style='{{iconStyle}}'></image> 
 </view>
  <view class='nav-title' wx:if="{{titleText && !titleImg}}">
  <text style='{{textStyle}}'>{{titleText}}</text>
  </view>
 </view>
 </view>

wxss:

.navbar{
 position: relative
}
.back-icon, .home-icon{
 width: 28px;
 height: 100%;
 position: absolute; 
 transform: translateY(-50%); 
 top: 50%; 
 display: flex;
 }
.back-icon{ 
 left: 16px;
}
.home-icon{ 
 left: 44px
}
.back-icon image{ 
 width: 28px; 
 height: 28px; 
 margin: auto;
}
.home-icon image{ 
 width: 20px; 
 height: 20px; 
 margin: auto;
}
.nav-title, .nav-icon{ 
 position: absolute; 
 transform: translate(-50%, -50%); 
 left: 50%; 
 top: 50%; 
 font-size: 0; 
 font-weight: bold;
}

运行效果图:

小程序实现自定义导航栏适配完美版

文字标题:

小程序实现自定义导航栏适配完美版

图片标题:

小程序实现自定义导航栏适配完美版

4、总结

经过小灰的一番论证以及实践经验,最终总结出以上最终解决方案,但希望对小伙伴们有所帮助,如果小伙伴们觉得有用,记得给颗star哦 --> 点我,后续还会更新其他组件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery操作单选按钮以及复选按钮示例
Sep 23 Javascript
JS、jquery实现几分钟前、几小时前、几天前等时间差显示效果的代码实例分享
Apr 11 Javascript
jQuery新窗口打开外链接
Jul 21 Javascript
BootStrap Table 获取同行不同列元素的方法
Dec 19 Javascript
javascript常用经典算法详解
Jan 11 Javascript
ES6中的箭头函数实例详解
Apr 06 Javascript
详解用webpack2搭建angular2的项目
Jun 22 Javascript
动态加载权限管理模块中的Vue组件
Jan 16 Javascript
JS实现求5的阶乘示例
Jan 21 Javascript
vue ajax 拦截原理与实现方法示例
Nov 29 Javascript
node.js中stream流中可读流和可写流的实现与使用方法实例分析
Feb 13 Javascript
详解vue 组件
Jun 11 Javascript
es6 symbol的实现方法示例
Apr 02 #Javascript
微信小程序设置全局请求URL及封装wx.request请求操作示例
Apr 02 #Javascript
Vue CLI 3.x 自动部署项目至服务器的方法
Apr 02 #Javascript
Vue 组件修改根实例的数据的方法
Apr 02 #Javascript
vue鼠标悬停事件实例详解
Apr 01 #Javascript
jquery简单实现纵向的无缝滚动代码实例
Apr 01 #jQuery
详解Vue前端对axios的封装和使用
Apr 01 #Javascript
You might like
DOTA2 1月28日更新:监管系统降临刀塔世界
2021/01/28 DOTA
PHP 代码规范小结
2012/03/08 PHP
真正根据utf8编码的规律来进行截取字符串的函数(utf8版sub_str )
2012/10/24 PHP
ubuntu10.04配置 nginx+php-fpm模式的详解
2013/06/03 PHP
PHP中执行MYSQL事务解决数据写入不完整等情况
2014/01/07 PHP
PHP中iconv函数转码时截断字符问题的解决方法
2015/01/21 PHP
PHP使用in_array函数检查数组中是否存在某个值
2015/03/25 PHP
php获取、检查类名、函数名、方法名的函数方法
2015/06/25 PHP
PHP实现路由映射到指定控制器
2016/08/13 PHP
jQuery中get()方法用法实例
2014/12/27 Javascript
JavaScript人脸识别技术及脸部识别JavaScript类库Tracking.js
2015/09/14 Javascript
JavaScript实现网页加载进度条代码超简单
2015/09/21 Javascript
JavaScript判断手机号运营商是移动、联通、电信还是其他(代码简单)
2015/09/25 Javascript
jQuery点击其他地方时菜单消失的实现方法
2016/04/22 Javascript
jQuery实现点击某个div打开层,点击其他div关闭层实例分析(阻止冒泡)
2016/11/18 Javascript
详解如何使用webpack打包Vue工程
2017/05/27 Javascript
JavaScript文件的同步和异步加载的实现代码
2017/08/19 Javascript
JS继承与闭包及JS实现继承的三种方式
2017/10/15 Javascript
基于Bootstrap表单验证功能
2017/11/17 Javascript
JavaScript数组排序小程序实现解析
2020/01/13 Javascript
[01:05:12]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS CIS-GAME
2014/05/21 DOTA
python抓取某汽车网数据解析html存入excel示例
2013/12/04 Python
python对json的相关操作实例详解
2017/01/04 Python
Python实现的破解字符串找茬游戏算法示例
2017/09/25 Python
详解python 拆包可迭代数据如tuple, list
2017/12/29 Python
Django values()和value_list()的使用
2020/03/31 Python
用python实现一个简单计算器(完整DEMO)
2020/10/14 Python
英国可持续奢侈品包包品牌:Elvis & Kresse
2018/08/05 全球购物
机电一体化专业应届本科生求职信
2013/09/27 职场文书
空乘英文求职信
2014/04/13 职场文书
母亲节演讲稿
2014/05/27 职场文书
2014光棍节大学生联谊活动方案
2014/10/10 职场文书
nginx搭建图片服务器的过程详解(root和alias的区别)
2021/03/31 Servers
Python requests用法和django后台处理详解
2022/03/19 Python
动画《新网球王子 U-17 WORLD CUP》希腊队PV公开
2022/04/02 日漫
java中如何截取字符串最后一位
2022/07/07 Java/Android