- 小程序自定义导航栏的开发原理及编码思路实践 (附带可直接使用的自定义导航栏组件)
1.引言 在小程序应用开发过程中,导航栏作为页面标题性的存在,不但起到了用户指引路由的作用,更是在应用功能较为完善和复杂的情况下,起到了进一步的功能性作用,小程序的原生导航栏如下: [图片] 显然,原生的导航栏除了能够提供标题,返回键等功能外,其他功能到目前为止并没有浮出水面。而为了定制符合我们自己开发要求的导航栏,此时,我们就需要对导航栏进行自定义的设计开发。自定义开发过导航栏效果如图: [图片] 2.原理及思路 (1)原理 首先我们要知道几个概念:状态栏,导航栏,导航栏胶囊,导航栏胶囊在导航栏中的上下边距 状态栏:是指通常手机顶部显示手机运营商,手机信号,手机电量等等信息的最顶层一栏。 导航栏:是指在小程序中显示胶囊按钮,返回键,标题的一栏。 导航栏胶囊:是指小程序中导航栏右部出现的胶囊状按钮,小程序中会一直置顶显示,在不同的机型中,胶囊的高度是固定的,目前均为32px。 导航栏胶囊在导航栏中的上下边距:胶囊按钮在导航中不是上下撑满的,是上下居中布局的,所以存在上下相等的边距。 效果说明图如下: [图片] 在小程序开发中,我们可以获取以下数据: 胶囊的布局位置及尺寸信息:(详情点击查看https://developers.weixin.qq.com/miniprogram/dev/api/ui/menu/wx.getMenuButtonBoundingClientRect.html) wx.getMenuButtonBoundingClientRect() (2)思路 原理我们都已经介绍过了,现在需要我们想一想设计的思路。 最常规的思路就是来个和导航栏一样宽度,一样高度的页面容器绝对定位覆盖在导航栏上面就可以了。然后在这个覆盖容器里面进行自定义发挥就可以了,保准自定义的内容和胶囊对齐的准准的,不会有任何问题。 那么,该怎么获取导航栏的高度和定位信息呢(宽度肯定是满宽,100vw)。 从上面的效果演示图我们可以知道,导航栏的高度是等于 胶囊高度+胶囊上边距 * 2 的,这个应该不难理解,胶囊高度上文已经提过,是固定的:32px,所以,我们只要再求出胶囊的上边距就可以了。上边距我们可以通过由 wx.getMenuButtonBoundingClientRect() 获取的胶囊距顶部的距离减去状态栏高度获取。从而计算出状态栏的高速。而后就可以实现我们一开始的思路,将一高度与导航栏相同,绝对定位在距屏幕顶部一个状态栏高度的距离便可以实现完全的导航栏精确覆盖。 3.代码实现 //胶囊上边框距顶部距离 const capsuleTop = wx.getMenuButtonBoundingClientRect().top; //状态栏高度 const statusBarHeight = wx.getSystemInfoSync().statusBarHeight; //药囊上边距状态栏下边的距离,即药囊在导航内容栏中的上下边距 const capsuleGap = capsuleTop - statusBarHeight; //导航内容栏的高度动态计算 const navContentHeight = capsuleGap * 2 + this.data.capsuleHeight; 4.注意事项。 (1)在定位好的自定义导航栏里编写内容时,不要与胶囊重合,否则会被胶囊覆盖,此时需要计算可使用区域的宽度,在计算宽度时,为了达到各机型效果的一致,需要根据当前模拟机型的宽度进行px对rpx的换算,才能使自定义组件中的内容的宽度在各个机型中效果一致。 (2)本文所述自定义导航栏的创建方法必须基于该自定义导航栏针对页面fixed绝对定位的基础上才可以。 5.结语 在编写自定义导航栏之前也查了很多材料,感觉都不太准,自己借鉴着摸索了一套自己的方法,请大家评判一番,我已将该自定义导航栏封装成了微信小程序自定义组件,插之即用,以供大家提高生产效率: NPM安装:https://www.npmjs.com/package/russell-weapp github:https://github.com/RussellCao824/russell-weapp
2020-06-07 - 【类知乎小房子】自定义返回键 自定义标题栏 自定义主页按钮 及参数计算
自定义顶部标题和左上角按钮方法解析及实践 前言 之前有兄台发过设置custom的方法 但是没有具体的实现方法 以至于很多不了解小程序的开发者不能循序渐进的理解制作自定义标题的方法 在这里详细总结了计算各参数的方法 我也写了一个自定义标题组件 只需要引用 直接在页面中调用即可 但因为掺杂了业务代码 需要整理过后会放出来 具体方法 首先在app.json中 将window.navigateionStyle 设置为custom [图片] 使用 wx.getSystemInfoSync 获取系统的属性 其中有顶部状态栏的高度 使用 wx.getMenuButtonBoundingClientRect 获取右上角胶囊菜单的相关属性 包括胶囊菜单的高度、相距上下左右屏幕的绝对位置 [图片] 如上图 我们需要获取四个参数 来确定整个标题栏的各项参数和左侧自定义胶囊的位置 获取顶部状态栏高度sys.statusBarHeight 具体代码 [代码]var sys= wx.getSystemInfoSync() var menu = wx.getMenuButtonBoundingClientRect() var statusHeight = menu.statusBarHeight var titleHeight = menu.height var titleRowWidth = sys.right - menu.right var titleColumnHeight = menu.top - menu.statusBarHeight [代码] 注意 小程序原生组件会遮挡自定义头部组件 如 canvas组件 input textarea的提示信息placeholder 该问题可以使用cover-view将头部定义为原生组件 设置层级解决 20191125后续更新 wx.getMenuButtonBoundingClientRect()返回undefined的情况 wx.getMenuButtonBoundingClientRect()在安卓和IOS端均会出现获取不到值的情况(返回undefined) 官方给出的答案是已经修复了该问题 但实际测试还是会出现类似问题 该问题与 平台 和 微信基础库 (随微信版本更新)无关 导致我们无法获取胶囊按钮的属性 进而无法计算header的高度 该问题极难复现 我在自己的真机上遇到过2次 在我的应用中出现概率不到1% 应对方法1: 官方建议延迟100MS 或 在返回undefined的情况下 重新获取一次 应对方法2: 判断平台 给与预估的默认值 IOS端和不同安卓端 IOS各机型的高度为44px 安卓端我测试最多的情况是48px 但安卓端实际情况需要具体测试 做进一步兼容 代码如下 [图片] 这里wx.getMenuButtonBoundingClientRect()方法在低版本微信中是不能用的 而且低版本的微信中不能使用wx.canIUse方法判断该方法是否存在 因此用捕获错误的方式兼容 在menu的属性返回undefined时 用我们预估的值去兼容 另外github.com有一个通过手机型号 返回手机各项参数的库 其中一项就是头部状态栏的高度 如果你想更准确的适配更多机型 可以使用这个库 无论哪种方法都不是最优的解决方案 大家酌情按照场景进行适配
2021-03-03 - 自定义navigationBar顶部导航栏,兼容适配所有机型(附完整案例)
前言 navigationBar相信大家都不陌生把?今天我们就来说说自定义navigationBar,把它改变成我们想要的样子(搜索框+胶囊、搜索框+返回按钮+胶囊等)。 思路 隐藏原生样式 获取胶囊按钮、状态栏相关数据以供后续计算 根据不同机型计算出该机型的导航栏高度,进行适配 编写新的导航栏 引用到页面 正文 一、隐藏原生的navigationBar window全局配置里有个参数:navigationStyle(导航栏样式),default=默认样式,custom=自定义样式。 [代码]"window": { "navigationStyle": "custom" } [代码] 让我们看看隐藏后的效果: [图片] 可以看到原生的navigationBar已经消失了,剩下孤零零的胶囊按钮,胶囊按钮是无法隐藏的。 二、准备工作 1.获取胶囊按钮的布局位置信息 我们用wx.getMenuButtonBoundingClientRect()【官方文档】获取胶囊按钮的布局位置信息,坐标信息以屏幕左上角为原点: [代码]const menuButtonInfo = wx.getMenuButtonBoundingClientRect(); [代码] width height top right bottom left 宽度 高度 上边界坐标 右边界坐标 下边界坐标 左边界坐标 下面是官方给的示意图,方便大家理解几个坐标。 [图片] 2.获取系统信息 用wx.getSystemInfoSync()【官方文档】获取系统信息,里面有个参数:statusBarHeight(状态栏高度),是我们后面计算整个导航栏的高度需要用到的。 [代码]const systemInfo = wx.getSystemInfoSync(); [代码] 三、计算公式 我们先要知道导航栏高度是怎么组成的, 计算公式:导航栏高度 = 状态栏高度 + 44。 实例 【源码下载】 自定义导航栏会应用到多个、甚至全部页面,所以封装成组件,方便调用;下面是我写的一个简单例子: app.js [代码]App({ onLaunch: function(options) { const that = this; // 获取系统信息 const systemInfo = wx.getSystemInfoSync(); // 胶囊按钮位置信息 const menuButtonInfo = wx.getMenuButtonBoundingClientRect(); // 导航栏高度 = 状态栏高度 + 44 that.globalData.navBarHeight = systemInfo.statusBarHeight + 44; that.globalData.menuRight = systemInfo.screenWidth - menuButtonInfo.right; that.globalData.menuBotton = menuButtonInfo.top - systemInfo.statusBarHeight; that.globalData.menuHeight = menuButtonInfo.height; }, // 数据都是根据当前机型进行计算,这样的方式兼容大部分机器 globalData: { navBarHeight: 0, // 导航栏高度 menuRight: 0, // 胶囊距右方间距(方保持左、右间距一致) menuBotton: 0, // 胶囊距底部间距(保持底部间距一致) menuHeight: 0, // 胶囊高度(自定义内容可与胶囊高度保证一致) } }) [代码] app.json [代码]{ "pages": [ "pages/index/index" ], "window": { "navigationStyle": "custom" }, "sitemapLocation": "sitemap.json" } [代码] 下面为组件代码: /components/navigation-bar/navigation-bar.wxml [代码]<!-- 自定义顶部栏 --> <view class="nav-bar" style="height:{{navBarHeight}}px;"> <input class="search" placeholder="输入关键词!" style="height:{{menuHeight}}px; min-height:{{menuHeight}}px; line-height:{menuHeight}}px; left:{{menuRight}}px; bottom:{{menuBotton}}px;"></input> </view> <!-- 内容区域: 自定义顶部栏用的fixed定位,会遮盖到下面内容,注意设置好间距 --> <view class="content" style="margin-top:{{navBarHeight}}px;"></view> [代码] /components/navigation-bar/navigation-bar.json [代码]{ "component": true } [代码] /components/navigation-bar/navigation-bar.js [代码]const app = getApp() Component({ properties: { // defaultData(父页面传递的数据-就是引用组件的页面) defaultData: { type: Object, value: { title: "我是默认标题" }, observer: function(newVal, oldVal) {} } }, data: { navBarHeight: app.globalData.navBarHeight, menuRight: app.globalData.menuRight, menuBotton: app.globalData.menuBotton, menuHeight: app.globalData.menuHeight, }, attached: function() {}, methods: {} }) [代码] /components/navigation-bar/navigation-bar.wxss [代码].nav-bar{ position: fixed; width: 100%; top: 0; color: #fff; background: #000;} .nav-bar .search{ width: 60%; color: #333; font-size: 14px; background: #fff; position: absolute; border-radius: 50px; background: #ddd; padding-left: 14px;} [代码] 以下是调用页面的代码,也就是引用组件的页面: /pages/index/index.wxml [代码]<navigation-bar default-data="{{defaultData}}"></navigation-bar> [代码] /pages/index/index.json [代码]{ "usingComponents": { "navigation-bar": "/components/navigation-bar/navigation-bar" } } [代码] /pages/index/index.js [代码]const app = getApp(); Page({ data: { // 组件参数设置,传递到组件 defaultData: { title: "我的主页", // 导航栏标题 } }, onLoad() { console.log(this.data.height) } }) [代码] 效果图: [图片] 好了,以上就是全部代码了,大家可以文中复制代码,也可以【下载源码】,直接到开发者工具里运行,记得appid用自己的或者测试哦! 下面附几张其它小程序的效果图,大家也可以尝试照着做: [图片][图片] 总结 本文写了自定义navigationBar的一些基础性东西,里面涉及组件用法、参数传递、导航栏相关。 由于测试环境有限,大家在使用时如果发现有什么问题,希望及时反馈,以供及时更新帮助更多的人! 大家有什么疑问,欢迎评论区留言!
2022-06-23