记一次小程序自定义导航栏及加载动画的解决方案

2,233 阅读3分钟

20190320163636.png

记一次小程序自定义导航栏及加载动画的解决方案

主要逻辑就是动态获取设备的 statusBarHeight 和 titleBarHeight,来设置导航栏的高度和 paddingTop

20190320162517.png

ip6

20190320162529.png

ipx

20190320163458.png

loading

导航栏是一个组件,自定义组件通过 properties 获得 prop 参数的,组件还需要维护 statusBarHeight,titleBarHeight 和 navigatorHeight(实际没用到) 这三个 data

通过在小程序 ready 生命周期内调用 setBarHeight 来动态获取这三个 data 变量

Component({
    properties: {
        title: {
            type: String,
            default: 'default title'
        },
        ifShowBtn: {
            type: Boolean,
            default: true
        }
    },
    data: {
        statusBarHeight: 0,
        titleBarHeight: 0,
        navigatorHeight: 0
    },
    ready: function () {
        this.setBarHeight()
    },

组件还有三个方法,这三个方法分别是:设置状态栏和标题栏高度的 setBarHeight、动态获取状态栏和标题栏高度的 getBarHeight,以及判断是否为 IOS 系统。

因为判断是否为 IOS 系统才能够设置 titleBarHeight,iPhone 或 iPad 的这个值为 44,安卓的统一设置为 48 即可

methods: {
        // 设置状态栏和标题栏高度
        setBarHeight: function () {
            this.isIOS().then(this.getBarHeight).then(res => {
                this.setData({
                    statusBarHeight: res.statusBarHeight,
                    titleBarHeight: res.titleBarHeight,
                    navigatorHeight: res.navigatorHeight
                })
            })
        },
        // 动态获取状态栏高度和标题栏高度
        getBarHeight: function (isIOS) {
            return new Promise((resolve, reject) => {
                wx.getSystemInfo.call(this, {
                    success: res => {
                        let statusBarHeight = res.statusBarHeight
                        let titleBarHeight = isIOS ? 44 : 48
                        resolve({ statusBarHeight, titleBarHeight, navigatorHeight: statusBarHeight + titleBarHeight })
                    },
                    failure: res => {
                        reject('error getting systeminfo')
                    }
                })
            })
        },
        // 判断是否为 IOS 系统
        isIOS: function () {
            return new Promise((resolve, reject) => {
                wx.getSystemInfo.call(this, {
                    success: res => {
                        if (res.model.indexOf('iPhone') > -1 || res.system.indexOf('iOS') > -1) {
                            resolve(true)
                        } else {
                            resolve(false)
                        }
                    },
                    failure: res => {
                        reject('error getting systeminfo')
                    }
                })
            })
        }

另外,在获得这些变量之后可以存入到 app 的 globalData 对象中,每次只需要从这个对象获取变量即可

然后编写 wxml:

<view style="height: {{titleBarHeight}}px; padding-top: {{statusBarHeight}}px;">
    <view class="header" style="height: {{titleBarHeight}}px; padding-top: {{statusBarHeight}}px;">
        <view wx:if="{{ifShowBtn}}" class="header-btn">
            <view class="btn-item">B</view>
            <view class="btn-item">H</view>
        </view>
        <view class="header-title">{{title}}</view>
    </view>
    <view class="loading">loading...</view>
</view>

自定义导航栏的高度就是 titleBarHeight,paddingTop 的值就是 statusBarHeight

因为自定义导航栏是 fixed 元素,因此这个 class 为 header 的 view 元素设置样式如下:

.header {
    display: flex;
    align-items: center;
    position: fixed; /* fixed 因此在 wxml 中还需要再次设置一遍 height 和 paddingTop */
    top: 0;
    background: #fff;
    width: 100%;
    z-index: 9999;
}

header-title 是一个绝对定位的元素,需要设置样式,将其居中:

.header-title {
    position: absolute;
    left: 50%;
    transform: translateX(-50%)
}

最后还需要解决 pullDownRefresh 的加载动画问题,如果没有修复这个问题会出现一个大的空白

20190320163140.png

20190320163157.png

20190320163205.png

首先需要设置 app.json

  • backgroundTextStyle 为 light
  • navigationBarTextStyle 为 black
{
  "pages": [
    "pages/index/index"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationStyle": "custom",
    "enablePullDownRefresh": true,
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTextStyle": "black"
  }
}

然后增加组件 wxml 中 class 为 loading 的元素这个就是自定义加载动画

然后增加样式:

.loading {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

flex 布局并居中即可

最后设置 navigator.json 将模块定义为组件

{
    "component": true
}

在页面中使用:

修改配置文件:

{
  "usingComponents": {
    "navigator": "../../components/navigator/navigator"
  }
}

修改 wxml 文件:

<navigator ifShowBtn="{{true}}" title="the navigator"></navigator>
<view class="container">
<!-- ...... -->
</view>

参考: