现成轮子网上很多,但是想实现自己的需求,还得自己再造一遍轮子,有一篇文章写的很好:微信小程序自定义navigationBar
✅保证安卓
和IOS
显示效果一致
拓展🉑️同时显示返回上一页
和返回首页
点击标题🉑️返回顶部
预留slot进行拓展
Component({ properties: { title: { // 标题 type: String, value: 'hello world', }, showGoBack: { // 显示返回按钮 type: Boolean, value: false, }, showHome: { // 显示返回主页按钮 type: Boolean, value: false, }, position: { // 是否开启绝对定位 type: Boolean, value: false, }, bgColor: { // 导航栏背景颜色 type: String, value: 'transparent', }, titleColor: { // 导航栏标题颜色 type: String, value: '#000000', }, showSlot: { // 是否开启slot type: Boolean, value: false, }, showBlankBlock: { // 是否开启空白块占位 type: Boolean, value: false, }, }, lifetimes: { async attached() { const systemInfo = await wx.getSystemInfo() const { statusBarHeight, windowWidth } = systemInfo const rightCapsule = wx.getMenuButtonBoundingClientRect() const { top, right, width, height } = rightCapsule const navBarYPadding = top - statusBarHeight const navBarXPadding = windowWidth - right const navBarHeight = height + (navBarYPadding * 2) const navBarBodyHeight = height const rightCapsuleWidth = width const styleData = `--bgColor: ${this.properties.bgColor}; --statusBarHeight: ${statusBarHeight}px; --navBarHeight: ${navBarHeight}px; --navBarBodyHeight: ${navBarBodyHeight}px; --navBarYPadding: ${navBarYPadding}px; --navBarXPadding: ${navBarXPadding}px; --rightCapsuleWidth: ${rightCapsuleWidth}px; --rightCapsuleHeight: ${navBarBodyHeight}px; --rightCapsuleRadius: ${navBarBodyHeight / 2}px; --titleColor: ${this.properties.titleColor}; ` const backIconUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAY9JREFUWEfFl88rBVEUgL/3Lyj/lbLzI6UoSlGEKAsWihBFKUpRFspCSSkWxIJYKIqFYqFYkJWsJJ06V6ep9969c+e9O6upmeb7zo85c6ZE4qOUmE+tBBo0sM9qAdZCYAqYVHAXsFlJomiBaWDCAAUuEmWPIgVmgTFD+gWagMN6CMwDIwb0DbQD+/XogSVg0ICk8QR+VA0u12NLsAL0G9Ab0Aac+cBjBVaBPgN6VviVLzxGYB3oMaAHhd+GwPMKbADdBnQDtAKPofA8AltApwFdAi3ASx54qMA20GFApwp/zwsPEdjRNDuWDBeJ/CsG7iuwAAwb0J7Cf2LhvgKjwFxKAWEnLYELPtuEJ1qKj5hShI7i7Gt4oc1Zl9fQBZp0EDmJNaDXpP5eR/FdaDlCS2Cfn/0YPanEdYhEjIBwloEBA3xViXNfiVgB4SwCQwYoC4nsBMc+EkUICCfpSuYCnQHGTdSylDYDB5UyUVQGHCO7lu/qsCrrULSAgJL+mLhIG/Wk6q5Qiwz4NP//PckF/gCIUUwhlNMi4AAAAABJRU5ErkJggg==' const homeIconUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAidJREFUWEft10+oD1EUwPHPW2BlI5KdkiQ7C2+l2LDxr+SxIJSQEiURCyz0ZEFECPm78KdeSVYSKcXKBjslxYJkJRtJ53VH86aZ38xv3u+3+53Vnbn3nPO95557zsyQ9rIJuzAdj3GijamhNkrYjUsF3TM40K29NgCHMZocHcXf3PNV7OwGoluAUziUHOzD+TTeg4tpfA9b8KcJSDcAV3K724HrBQebcQ3T8CRB/KyDaAIwFXcwgt/YjvsVhtckiFl4mSA+d4KoA5iN21iB78l57K6TLMUNzMPbBPG+SqETwILkfAk+IUL8qi6kaX4h7mIxPibd12W6VQDDKezz8Q5x5yt3UQE1Ew+xDN8SxNPi2jKAlcl5nOMbrMeXhjsvW/YIkRuRPxHFsfyiIsDG5HwKnmEtfk3CeaYaSRzOQ7bhVjaRB4iyejlNBPW6HjjOmziL/enFXlyIcQYQxSWKTEjQBWU/5AhOJsMxHg2AVamZxPtzOcp+AITNKNVR1EJWB8BxHCvpZvG+l1K0N+4zACLcUTjy8gLLe+kdz9OVzJsdyXJgAxalmSDrJ0D23fAAH4rXMIpGkPYTICIb9selDUAc2daK44kbdLNiLjuCSQEcxOma3IgQlyVwTwDyRso4Oh1fTwHKekhd/gwABhEYRGAQgUYRmIEfNaW2qlHNwdcGLXxCESuraNFsoiXPLTEWzqPW/+9mhTXxfxitPb6oixJw8fM6oU/8A8+oq0Iv6rN4AAAAAElFTkSuQmCC' this.setData({ statusBarHeight, navBarHeight, navBarBodyHeight, navBarYPadding, navBarXPadding, rightCapsuleWidth, styleData, backIconUrl, homeIconUrl, }) }, }, data: { statusBarHeight: 20, // 状态栏高度 navBarHeight: 40, // 导航栏高度 navBarBodyHeight: 32, // 导航栏内容高度 navBarYPadding: 4, // 导航栏Y轴内间距 navBarXPadding: 8, // 导航栏X轴内间距 rightCapsuleWidth: 87, // 右边胶囊宽度 styleData: '', // 样式变量 backIconUrl: '', // 返回icon homeIconUrl: '', // 主页icon }, methods: { goBack() { // console.log('goBack'); const pages = getCurrentPages() // 单曲页面栈小于等于一个页面,直接返回首页 if (pages.length <= 1) { this.goHome() } else { wx.navigateBack() } }, goHome() { // console.log('goHome'); // 小程序中页面栈最多十层 // 返回的页面数,如果 delta 大于现有页面数,则返回到首页。 wx.navigateBack({ delta: 10 }) }, backTop() { wx.pageScrollTo({ scrollTop: 0, duration: 300 }) }, } })
index.wxml
<view style="{{styleData}}"> <view class="c-navbar {{position ? 'c-navbar--position' : ''}}"> <!-- 状态栏 --> <view class="c-navbar__status-bar"></view> <!-- 导航栏 --> <view class="c-navbar__body" wx:if="{{!showSlot}}"> <!-- 导航栏左边 => 胶囊 --> <view class="c-navbar__body__left"> <view class="c-navbar__body__left__back" wx:if="{{showGoBack && (!showHome)}}" bindtap="goBack"> <image src="{{backIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__icon--back"></image> <text>返回</text> </view> <view class="c-navbar__body__left__home" wx:if="{{showGoBack && showHome}}"> <view class="c-navbar__body__left__home__back" bindtap="goBack"> <image src="{{backIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__home--back"></image> </view> <view class="c-navbar__body__left__home--division"></view> <view class="c-navbar__body__left__home__home" bindtap="goHome"> <image src="{{homeIconUrl}}" class="c-navbar__body__icon c-navbar__body__left__home--home"></image> </view> </view> </view> <!-- 导航栏中间 => 标题 --> <view class="c-navbar__body__title" bindtap="backTop"> {{title}} </view> <!-- 导航栏右边 => 胶囊 --> <view class="c-navbar__body__right"></view> </view> <!-- 开启slot --> <view class="c-navbar__body" wx:if="{{showSlot}}"> <view class="c-navbar__body--slot"> <slot></slot> </view> <!-- 导航栏右边 => 胶囊 --> <view class="c-navbar__body__right"></view> </view> </view> <!-- 空白块占位符, 用于解决下拉刷新导航栏掉下来的问题, 需要配合开启position --> <view class="c-blank-block" wx:if="{{showBlankBlock}}"></view> </view>
index.wxss
.c-navbar { position: -webkit-sticky; position: sticky; top: 0; left: 0; z-index: 9999; width: 100vw; box-sizing: border-box; background-color: var(--bgColor); } .c-navbar--position { position: fixed; } .c-navbar__status-bar { width: 100vw; height: var(--statusBarHeight); } .c-navbar__body { width: 100vw; height: var(--navBarHeight); padding: 0 var(--navBarXPadding); overflow: hidden; box-sizing: border-box; overflow: hidden; display: -webkit-flex; display: flex; /* -webkit-justify-content: center; justify-content: center; */ -webkit-align-items: center; align-items: center; flex-wrap: wrap; } .c-navbar__body__left { width: var(--rightCapsuleWidth); height: var(--rightCapsuleHeight); box-sizing: border-box; font-size: 16px; font-weight: 500; display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; flex-wrap: wrap; } .c-navbar__body__title { box-sizing: border-box; flex: 1; padding: 0 var(--navBarXPadding); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--titleColor); font-size: 18px; font-weight: 500; } .c-navbar__body__right { width: var(--rightCapsuleWidth); height: var(--rightCapsuleHeight); } .c-navbar__body__icon { display: inline-block; width: 20px; height: 20px; } .c-navbar__body__left__back { height: 100%; background-color: rgba(255, 255, 255, .6); border: 1px solid rgba(0, 0, 0, .1); border-radius: var(--rightCapsuleRadius); box-sizing: border-box; padding: 0 calc(var(--navBarXPadding) * 2); display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; flex-wrap: wrap; } .c-navbar__body__left__icon--back { margin-left: -5px; } .c-navbar__body__left__home { position: relative; width: 100%; height: 100%; background-color: rgba(255, 255, 255, .6); border: 1px solid rgba(0, 0, 0, .1); border-radius: var(--rightCapsuleRadius); box-sizing: border-box; display: -webkit-flex; display: flex; } .c-navbar__body__left__home__back { flex: 1; display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; flex-wrap: wrap; } .c-navbar__body__left__home__home { flex: 1; display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; flex-wrap: wrap; } .c-navbar__body__left__home--back { width: 22px; height: 22px; box-sizing: border-box; } .c-navbar__body__left__home--home { width: 19px; height: 19px; box-sizing: border-box; } .c-navbar__body__left__home--division { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 1px; height: 20px; background-color: rgba(0, 0, 0, .1); } .c-navbar__body--slot { flex: 1; } .c-blank-block { width: 100vw; height: calc(var(--statusBarHeight) + var(--navBarHeight)); background-color: transparent; }
index.json
{ "component": true, "usingComponents": {} }
属性
属性 描述 默认值
title 标题 hello world
showGoBack 显示返回按钮 false
showHome 显示返回主页按钮 false
position 是否开启绝对定位 false
bgColor 导航栏背景颜色 white
titleColor 导航栏标题颜色 #000000
showSlot 是否开启slot false
showBlankBlock 是否开启空白块占位 false
使用
index.json
{ "usingComponents": { "wmp-navbar": "@chenbz/wmp-navbar" }, "navigationStyle": "custom" }
index.wxml
<view> <wmp-navbar title="标题"></wmp-navbar> </view>
npm
组件已打包发布到npm,欢迎移步至@chenbz/wmp-navbar
原文链接:https://blog.csdn.net/weixin_42863549/article/details/126449900