小程序-自定义导航栏

120 阅读3分钟

做了一段时间的小程序开发工作,也获得来不少的开发经验,在这里分享一下开发过程中遇到的问题,或者是比较认为比较好的封装。小程序从开始的项目搭建,到后面一些页面的开发,基本上都我一个人参与开发的,其中框架的搭建也借鉴了网上的很多好的实践。

我们的小程序是在uniapp基础上开发的。因为我们要兼容的平台,包含微信小程序,百度小程序、支付宝小程序等。

话不多说,下面是对导航栏的封装。

<template>
  <customBar :showBackButton="true" title="标题" @back="goback" :marginTop="20">
    <view class="dd">
     
    </view>
  </customBar>
</template>
import customBar from '@/pages/components/custom-bar';
<template>
    <view class="c-custom-page">
        <view class="custom-bar">
            <!-- 状态栏占位 -->
            <view class="status_bar" :style="{ height: systemHeightInfo.statusBarHeight + 'rpx' }"></view>
            <!-- 自定义导航栏 -->
            <uni-nav-bar fixed class="customContent"  :border="false" :style="{ top: systemHeightInfo.statusBarHeight + 'rpx' }">
​
                <slot name="title">
                    <view class="custom-title">{{ calcTitle(title) }}</view>
                </slot>
                <template v-slot:left>
                    <slot name="cLeft">
                        <!-- #ifdef MP-WEIXIN -->
                        <view class="custom-left" v-if="showBackButton" @click="goBack">
                            <view class="custom-left-icon"></view>
                        </view>
                        <!-- #endif -->
                    </slot>
                    <!-- #ifdef MP-BAIDU -->
                
                    <!-- #endif -->
                </template>
            </uni-nav-bar>
        </view>
        <view :style="{
            marginTop: systemHeightInfo.statusBarHeight + 88  + marginTop +  'rpx'
        }">
            <slot></slot>
​
        </view>
    </view>
</template>
<script>
import { systemHeightInfo } from '@/utils/authUtils';
import { uniNavBar } from '@dcloudio/uni-ui'
export default {
    data() {
        return {
            systemHeightInfo: null,
        }
    },
    props: {
        title: {
            type: String,
            default: '标题'
        },
        showBackButton: {
            type: Boolean,
            default: true
        },
        marginTop:{
            type: Number,
            default: 0
        }
    },
    components: {
        uniNavBar
    },
    created() {
        this.systemHeightInfo = systemHeightInfo()
    },
    methods: {
        goBack() {
            this.$emit('back')
        },
        calcTitle(val) {
            if (!val) return '详情'
            if (val && val.length > 15) {
                return val.slice(0, 15) + '...'
            } else {
                return val
            }
        },
    }
}
​
​
</script>
​
​
<style scoped lang="scss">
.c-custom-page {
   
}
.custom-bar {
    position: relative;
    z-index: 999999;
    background-color: #fff;
    width: 100%;
}
​
.status_bar {
    height: var(--status-bar-height);
    width: 100%;
    position: fixed;
    top: 0;
    background: #fff;
    z-index: 998;
}
​
.customContent {
    position: fixed;
    height: 88rpx;
    background: #fff;
    top: var(--status-bar-height);
    width: 100%;
    z-index: 998;
}
​
.custom-title {
    width: 150rpx;
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: center;
    padding: 0 20rpx;
    height: 88rpx;
    color: #333;
    font-size: 32rpx;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    word-break: break-all;
}
​
.custom-left {
    width: 150rpx;
    height: 100%;
    height: 88rpx;
    display: flex;
    align-items: center;
​
    .uni-navbar__header-btns-left {
        width: 150rpx !important;
    }
​
    .custom-left-text {
        font-size: 28rpx;
        color: #333;
        position: relative;
        margin-right: 10rpx;
    }
​
    .custom-left-icon {
        position: absolute;
        top: 50%;
        left: 20rpx;
        width: 18rpx;
        height: 18rpx;
        border: 4rpx solid #333;
        transform: rotate(45deg) translate(0, -50%);
        border-right-color: transparent;
        border-top-color: transparent;
    }
    .bd-left-icon {
        width: 120rpx;
        height: 80rpx;
        background-color: #fff;
    }
}
</style>
// @/utils/authUtils
export const systemHeightInfo = function () {
    /****************** 所有平台共有的系统信息 ********************/
    // 设备系统信息
    let systemInfomations = uni.getSystemInfoSync()
    // 机型适配比例系数
    let scaleFactor = 750 / systemInfomations.windowWidth
    // 当前机型-屏幕高度
    let windowHeight = systemInfomations.windowHeight * scaleFactor //rpx
    // 当前机型-屏幕宽度
    let windowWidth = systemInfomations.windowWidth * scaleFactor //rpx
    // 状态栏高度
    let statusBarHeight = (systemInfomations.statusBarHeight) * scaleFactor //rpx

    // 导航栏高度  注意:此导航栏高度只针对微信小程序有效 其他平台如自定义导航栏请使用:状态栏高度+自定义文本高度
    let navHeight = 0 //rpx

    /****************** 微信小程序头部胶囊信息 ********************/
    // #ifdef MP-WEIXIN
    const menuButtonInfo = wx.getMenuButtonBoundingClientRect()
    // 胶囊高度
    let menuButtonHeight = menuButtonInfo.height * scaleFactor //rpx
    // 胶囊宽度
    let menuButtonWidth = menuButtonInfo.width * scaleFactor //rpx
    // 胶囊上边界的坐标
    let menuButtonTop = menuButtonInfo.top * scaleFactor //rpx
    // 胶囊右边界的坐标
    let menuButtonRight = menuButtonInfo.right * scaleFactor //rpx
    // 胶囊下边界的坐标
    let menuButtonBottom = menuButtonInfo.bottom * scaleFactor //rpx
    // 胶囊左边界的坐标
    let menuButtonLeft = menuButtonInfo.left * scaleFactor //rpx

    // 微信小程序中导航栏高度 = 胶囊高度 + (顶部距离 - 状态栏高度) * 2
    navHeight = menuButtonHeight + (menuButtonTop - statusBarHeight) * 2
    // #endif


    // #ifdef MP-WEIXIN
    return {
        scaleFactor,
        windowHeight,
        windowWidth,
        statusBarHeight,
        menuButtonHeight,
        menuButtonWidth,
        menuButtonTop,
        menuButtonRight,
        menuButtonBottom,
        menuButtonLeft,
        navHeight
    }
    // #endif

    // #ifndef MP-WEIXIN
    return {
        scaleFactor,
        windowHeight,
        windowWidth,
        statusBarHeight
    }
    // #endif
}