天天看点

微信小程序自定义导航栏(模板化)

前段时间写过一篇关于微信小程序自定义导航栏的自定义组件,但是对于分享页有一定的bug

这次用模板化又搞了一遍 优化了下Android与IOS 显示更接近微信原生的导航栏,以及修复分享页面不显示返回首页按钮

如果大家不习惯模板化的话可以 针对自己的需求拿以前封装的组件化做一些修改

微信小程序自定义导航栏(组件化)

CustomNavBar.wxml

<template name="CustomNavBar">
	<block wx:if="{{ showNavBar }}">

		<!-- 自定义导航栏悬浮时,卡空行 -->
		<block wx:if="{{ needFixed }}">
			<view style="position: relative; width: 100%; height: {{ navHeight }}px;"></view>
		</block>

		<view class="custom-navbar-con relative {{ iOS ? ' ios ' : ' android ' }}" style="height: {{ navHeight }}px; {{ needFixed ? 'position: fixed; top: 0;' : '' }}">
			<view class="custom-navbar-statusbar-con relative" style="height: {{ statusBarHeight }}px;"></view>
			<view class="custom-navbar-content relative" style="height: {{ navHeight - statusBarHeight }}px;">

				<!-- iOS端的导航栏显示方式 -->
				<block wx:if="{{ navTitle && navTitle.length > 0 }}">
					<view class="custom-navbar-title ios">{{ navTitle }}</view>
				</block>

				<block wx:if="{{ showLeftMenu }}">
					<view class="custom-navbar-left-menu-con clearfix" style="top: {{ navRightMenuRect.top - statusBarHeight - 1 }}px; left: {{ winWidth - navRightMenuRect.right }}px; height: {{ navRightMenuRect.height + 2 }}px;">
						<block wx:if="{{ showBackBtn }}">
							<view class="custom-navbar-icon-btn pull-left back" style="height: {{ navRightMenuRect.height }}px" bindtap="customNavBarBack">
								<image class="icon" src="../../image/icon-nav-back.png" mode="aspectFit" style="width: {{ navRightMenuRect.height }}px;" />
								<text class="text"></text>
							</view>
						</block>

						<block wx:if="{{ showHomeBtn }}">
							<view class="custom-navbar-icon-btn pull-left home" style="height: {{ navRightMenuRect.height }}px"  bindtap="customNavBarBackToHome">
								<image class="icon" src="../../image/icon-nav-home.png" mode="aspectFit" style="width: {{ navRightMenuRect.height }}px;" />
								<text class="text"></text>
							</view>
						</block>

						<!-- android端的导航栏显示方式 -->
						<block wx:if="{{ navTitle && navTitle.length > 0 }}">
							<view class="custom-navbar-title android pull-left" style="line-height: {{ navRightMenuRect.height - 2 }}px;">{{ navTitle }}</view>
						</block>
					</view>
				</block>
			</view>
		</view>
	</block>
</template>

           

CustomNavBar.wxss

.custom-navbar-con { position: relative; width: 100%; background-color: white; z-index: 9999; }
.custom-navbar-con .custom-navbar-statusbar-con { width: 100%; }
.custom-navbar-con .custom-navbar-content { width: 100%; }
.custom-navbar-con .custom-navbar-left-menu-con { position: absolute; }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn { height: 100%; border-radius: 200px; border: 1px solid rgba(220, 220, 220, 0.6); }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn .icon { height: 90%; margin-top: 2.5%; }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn .text { font-size: 27rpx; }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn.back { border: none; }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn.back~.custom-navbar-icon-btn.home { margin-left: 10rpx; }
.custom-navbar-con .custom-navbar-left-menu-con .custom-navbar-icon-btn.switch-shop { padding-left: 5px; padding-right: 25rpx; }


.custom-navbar-con.ios .custom-navbar-title.android { display: none; }
.custom-navbar-con.android .custom-navbar-title.ios { display: none; }
.custom-navbar-con .custom-navbar-title.ios { font-weight: bold; text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); }
.custom-navbar-con .custom-navbar-title.android { padding-left: 30rpx; }```
CustomNavBar.js

```javascript
module.exports = function(PageInstance) {
	let App = getApp()

	let _tplData = {
		_CustomNavBar_: {
			navRightMenuRect: App.NavRightMenuRect,
			navRightMenuCenterY: App.NavRightMenuCenterY,
			statusBarHeight: App.StatusBarHeight,
			winWidth: App.WinWidth,
			winHeight: App.WinHeight,
			iOS: App.iOS,

			navTitle: '', // 当前只合适短标题,如需长标题,建议隐藏自定义导航栏,自定义展示
			navHeight: App.CustomNavHeight,

			needFixed: false,

			showNavBar: !App.NavRightMenuRect ? false : true,
			showLeftMenu: true,
			showBackBtn: true,
			showHomeBtn: false
		}
	}

	let _tplMethods = {
		customNavBarBack() {
			wx.navigateBack()
		},
		customNavBarBackToHome() {
			let url = '/pages/index/index'
			wx.reLaunch({
				url: url
			})
		}
	}
	let isIndexPage = !!(PageInstance.route == 'pages/index/index')
	let pages = getCurrentPages()
	if (pages.length == 1) {
		_tplData._CustomNavBar_.showBackBtn = false
		_tplData._CustomNavBar_.showHomeBtn = !isIndexPage
	}

	// 每个页面 可单独配置自定义导航栏
	if (PageInstance.data.CustomNavBarConfig) {
		Object.assign(_tplData._CustomNavBar_, PageInstance.data.CustomNavBarConfig)
	}

	// !!!! 最后执行
	// 当无法获取到右上角按钮胶囊的布局位置时,强制设置自定义导航栏为隐藏状态
	if (!App.NavRightMenuRect) {
		_tplData._CustomNavBar_.showNavBar = false
	}

	Object.assign(PageInstance, _tplMethods)
	PageInstance.setData(_tplData)
	return this
}

           

app.js的配置

// 自定义导航栏
import CustomNavBar from './template/CustomNavBar/CustomNavBar';

 App({
 	//自定义 模板式 组件
	CustomNavBar,
 
 	// 系统信息
    WinWidth: 0,
    WinHeight: 0,
    StatusBarHeight: 0,
    PixelRatio: 1,
    SystemFullName: '',
    SystemVersion: '',
    SystemSDKVersion: '',

    //自定义导航栏相关
    NavRightMenuRect: null,
    NavRightMenuCenterY: 0,
    CustomNavHeight: 0,
    
	onLaunch: function (options) {
		let self = this
		let systemInfo = wx.getSystemInfoSync()
		self.iOS = systemInfo.platform === 'ios'
		self.isDebug = systemInfo.platform === 'devtools'
		if (self.isDebug) {
			// 单纯为了在开发工具下调试 自定义导航栏
			// 开发工具下不存在App版本号的区分
			systemInfo.version = '7.0.0'
		}
		self.WinWidth = systemInfo.windowWidth
		self.WinHeight = systemInfo.windowHeight
		self.StatusBarHeight = systemInfo.statusBarHeight
		// 部分小程序库版本没有返回状态栏高度
		if (!self.StatusBarHeight) {
			self.StatusBarHeight = 20
		}
		self.PixelRatio = Math.max(systemInfo.pixelRatio, 2)
		self.SystemFullName = systemInfo.system
		self.SystemVersion = systemInfo.version
		self.SystemSDKVersion = systemInfo.SDKVersion

		// app.json全局配置的自定义导航栏的话,客户端需求版本为6.6.0
		// 每个页面 单独配置的自定义导航栏的话,客户端需求版本为7.0.0
		// wx.getMenuButtonBoundingClientRect方法,要求基础库版本为2.1.0
		if (self.compareVersion(self.SystemVersion, '6.6.0') >= 0) {
			// 官方的6.6.0版本以上客户端,最低基础库版本为1.9.4
			// 6.6.0以上且[1.9.4 - 2.1.0]范围内的机型无法使用wx.getMenuButtonBoundingClientRect
			// 所以手动写死非全面屏手机的适配胶囊布局位置
			self.NavRightMenuRect = {
				top: 26,
				bottom: 58,
				right: self.WinWidth - 10,
				width: 87,
				height: 32
			}
			// 如果系统信息返回的状态栏高度大于20,认为是全面屏手机
			if (self.StatusBarHeight > 20) {
				self.NavRightMenuRect.top = 50
				self.NavRightMenuRect.bottom = 82
			}

			// 2019年08月21日22:09:22
			// 微信小程序库出现bug,导致部分机型wx.getMenuButtonBoundingClientRect无返回值
			// 所以在这之前先默认写死一个NavRightMenuRect,防止全局的自定义导航栏已经隐藏了但是无法显示自定义导航栏
			// 详见https://developers.weixin.qq.com/community/develop/doc/00062238d78e880aedd88b72351c00
			if (wx.getMenuButtonBoundingClientRect) {
				let NavRightMenuRect = wx.getMenuButtonBoundingClientRect()
				self.NavRightMenuRect = {
					top: NavRightMenuRect.top,
					bottom: NavRightMenuRect.bottom,
					right: NavRightMenuRect.right,
					width: NavRightMenuRect.width,
					height: NavRightMenuRect.height
				}
			}

			self.NavRightMenuCenterY = self.NavRightMenuRect.top + self.NavRightMenuRect.height / 2
			self.CustomNavHeight = self.NavRightMenuRect.bottom + (self.NavRightMenuRect.top - self.StatusBarHeight)
		} else {
			self.NavRightMenuRect = null
			self.CustomNavHeight = 0
		}
	},
	
    // 比较两个版本号
	compareVersion (v1, v2) => {
	    v1 = v1.split('.')
	    v2 = v2.split('.')
	    const len = Math.max(v1.length, v2.length)
	
	    while (v1.length < len) {
	        v1.push('0')
	    }
	    while (v2.length < len) {
	        v2.push('0')
	    }
	
	    for (let i = 0; i < len; i++) {
	        const num1 = parseInt(v1[i])
	        const num2 = parseInt(v2[i])
	
	        if (num1 > num2) {
	            return 1
	        } else if (num1 < num2) {
	            return -1
	        }
	    }
	    return 0
	} 
       
}),


           

假如在index 页面引用

index.wxml

<!-- 自定义NavBar -->
	<import src="../../template/CustomNavBar/CustomNavBar.wxml" />
	<template is="CustomNavBar" data="{{ ..._CustomNavBar_ }}"></template>
           

index.js

onLoad: function(options) {
		new App.CustomNavBar(this)
	}