当前位置: 首页 > news >正文

《UniApp 安全区适配与自定义导航栏全攻略》

           在 UniApp 开发原生 App(比如用 HBuilderX 打包成 Android / iOS)时,要预留手机的系统状态栏(即顶部信号、电量栏)空间,否则内容会被顶到最上方被遮住。

⚠️ 注意事项

  1. App 端的状态栏一般为 24–44px(取决于设备和刘海屏)。

  2. iPhone X 以上需同时考虑 顶部状态栏 + 底部安全区

  3. 如果使用 <page-meta> 设置导航栏为透明,也要保留 status-bar

  4. HBuilderX 运行时调试时,只有 真机预览或打包后 才能看到真实安全区效果。

场景变量含义
iPhone X 刘海屏headerSafeHeight顶部留出状态栏空间
带 Home 指示条的设备bottomSafeHeight底部留出安全区
横屏设备或PadleftSafeWidth / rightSafeWidth侧边安全区

提示

  • App 真机运行 时才会正确返回 safeAreaInsets
    模拟器/H5 里返回 0 是正常的。

  • 如果页面使用了自定义导航栏,必须手动加上 <view :style="{height: headerSafeHeight+'px'}"></view>

模块说明是否包含
状态栏预留(var(--status-bar-height))自动适配刘海屏✔️
动态获取 safeAreaInsets手动控制 / JS方式✔️
封装 safeAreaMixin支持 top/bottom/left/right✔️
封装自定义导航栏可复用组件✔️
App、小程序、H5 平台兼容各平台都考虑到了✔️
返回逻辑处理页面栈判断(navigateBack/switchTab)✔️
插槽 + 动态样式支持左右插槽、右侧按钮✔️
关闭系统导航栏配置navigationStyle: "custom"✔️
状态栏占位 + 内容区域顶部 + 底部安全区布局✔️

一、官方推荐方式:使用 status-bar 占位区(最简单)

UniApp 内置了系统状态栏的安全区变量,可以自动适配不同手机。

📱 var(--status-bar-height)UniApp 提供的全局 CSS 变量,在 App 端和小程序端都能自动匹配手机状态栏高度(包括刘海屏)。

<template><view class="page"><!-- ✅ 状态栏占位 --><view class="status-bar"></view><!-- 页面内容 --><view class="content"><text>这是主内容区域</text></view></view>
</template><style>
.status-bar {height: var(--status-bar-height); /* 自动适配刘海/状态栏高度 */width: 100%;background-color: #ffffff; /* 可自定义颜色 */
}
.content {flex: 1;background-color: #f5f5f5;
}
</style>

二、使用 JavaScript 获取安全区信息(更灵活)

如果你需要在脚本中动态设置(比如传给子组件):

onLoad() {const info = uni.getSystemInfoSync();console.log('状态栏高度:', info.statusBarHeight);this.statusBarHeight = info.statusBarHeight;
}

然后在模板中用:

<view :style="{ height: statusBarHeight + 'px' }"></view>

三、推荐封装方式(可复用)

建一个 safeAreaMixin.js(很多项目这样做):

// /mixins/safeAreaMixin.js/*** 安全区域适配混入* 用于自动适配顶部状态栏和底部安全区*/
export default {data() {return {safeAreaInsetsTop: 0,     // 顶部安全区高度safeAreaInsetsBottom: 0,  // 底部安全区高度safeAreaInsetsLeft: 0,safeAreaInsetsRight: 0,statusBarHeight: 0,       // 状态栏高度isH5: false,isApp: false}},computed: {/** ✅ 顶部安全区高度(App、微信小程序会生效) */headerSafeHeight() {// H5 不需要状态栏占位// #ifdef H5return 0// #endif// 其他平台返回状态栏高度或安全区顶部高度return this.safeAreaInsetsTop || this.statusBarHeight || 0},/** ✅ 底部安全区高度(适配 iPhone X 系列) */bottomSafeHeight() {// #ifdef H5return 0// #endifreturn this.safeAreaInsetsBottom || 0},/** ✅ 左右安全边距 */leftSafeWidth() {return this.safeAreaInsetsLeft || 0},rightSafeWidth() {return this.safeAreaInsetsRight || 0}},onLoad() {this.initSafeArea()},methods: {/** 初始化安全区域信息 */initSafeArea() {// 平台标识// #ifdef H5this.isH5 = true// #endif// #ifdef APP-PLUSthis.isApp = true// #endifconst systemInfo = uni.getSystemInfoSync()// 状态栏高度this.statusBarHeight = systemInfo.statusBarHeight || 0// 优先使用 safeAreaInsets(新版本)if (systemInfo.safeAreaInsets) {const { top, bottom, left, right } = systemInfo.safeAreaInsetsthis.safeAreaInsetsTop = top || this.statusBarHeightthis.safeAreaInsetsBottom = bottom || 0this.safeAreaInsetsLeft = left || 0this.safeAreaInsetsRight = right || 0}// 旧版兼容 safeAreaelse if (systemInfo.safeArea) {const safeArea = systemInfo.safeAreathis.safeAreaInsetsTop = safeArea.top || this.statusBarHeightthis.safeAreaInsetsBottom = systemInfo.screenHeight - safeArea.bottomthis.safeAreaInsetsLeft = safeArea.left || 0this.safeAreaInsetsRight = systemInfo.screenWidth - safeArea.right}// 如果顶部安全区为 0,但有状态栏高度 → 用状态栏高度兜底if (!this.safeAreaInsetsTop && this.statusBarHeight) {this.safeAreaInsetsTop = this.statusBarHeight}}}
}

在页面中引入:

import safeAreaMixin from '@/mixins/safeAreaMixin.js'export default {mixins: [safeAreaMixin],// ...
}

在模板中使用:

<view class="page"><!-- 顶部安全区 --><view class="safe-top" :style="{ height: headerSafeHeight + 'px' }"></view><view class="content">页面内容</view><!-- 底部安全区 --><view class="safe-bottom" :style="{ height: bottomSafeHeight + 'px' }"></view>
</view>

四、封装一个 通用的自定义导航栏组件,适配 App / 小程序 / H5,自动处理 安全区 + 状态栏高度 + 返回按钮 + 标题 + 右侧操作按钮

📦 1、文件结构

components/
└── CustomNavBar/
└── CustomNavBar.vue
mixins/
└── safeAreaMixin.js   (前面写过这个)

🧱 2、CustomNavBar.vue 代码

<template><view class="custom-navbar"><!-- 顶部安全区 --><view :style="{ height: headerSafeHeight + 'px' }"></view><!-- 实际导航栏 --><view class="navbar" :style="navbarStyle"><!-- 左侧:返回按钮 --><view class="nav-left"><imagev-if="showBack"class="back-icon"src="/static/icon/back.svg"mode="aspectFit"@tap="handleBack"/><slot name="left"></slot></view><!-- 中间:标题 --><view class="nav-title"><text>{{ title }}</text></view><!-- 右侧:按钮或自定义插槽 --><view class="nav-right"><slot name="right"><text v-if="rightText" class="right-text" @tap="onRightTap">{{ rightText }}</text></slot></view></view></view>
</template><script>
import safeAreaMixin from '@/mixins/safeAreaMixin.js'export default {name: 'CustomNavBar',mixins: [safeAreaMixin],props: {title: {type: String,default: ''},showBack: {type: Boolean,default: true},rightText: {type: String,default: ''},bgColor: {type: String,default: '#FFFFFF'},textColor: {type: String,default: '#0D0D0D'},border: {type: Boolean,default: true}},computed: {navbarStyle() {return {backgroundColor: this.bgColor,color: this.textColor,borderBottom: this.border ? '2rpx solid #f0f0f0' : 'none'}}},methods: {handleBack() {// 如果页面栈只有1个,则返回首页const pages = getCurrentPages()if (pages.length === 1) {uni.switchTab({ url: '/pages/home/index' })} else {uni.navigateBack()}},onRightTap() {this.$emit('right-click')}}
}
</script><style scoped lang="scss">
.custom-navbar {width: 100%;
}.navbar {height: 88rpx;display: flex;align-items: center;justify-content: space-between;padding: 0 32rpx;box-sizing: border-box;
}.nav-left,
.nav-right {width: 120rpx;display: flex;align-items: center;justify-content: center;
}.nav-title {flex: 1;text-align: center;font-size: 32rpx;font-weight: 500;
}.back-icon {width: 48rpx;height: 48rpx;
}.right-text {font-size: 28rpx;color: #ff1a47;
}
</style>

🚀 3、在页面中使用

在需要的页面顶部关闭系统导航栏:

{"navigationStyle": "custom"
}

然后在页面模板中:

<template><view class="page"><CustomNavBartitle="商品詳情"rightText="分享"@right-click="onShare"/><scroll-view scroll-y class="content"><!-- 页面内容 --></scroll-view></view>
</template><script>
import CustomNavBar from '@/components/CustomNavBar/CustomNavBar.vue'export default {components: { CustomNavBar },methods: {onShare() {uni.showToast({ title: '点击了分享', icon: 'none' })}}
}
</script>

✨ 4、支持插槽扩展

还可以像这样使用自定义左右区域:

<CustomNavBar title="首頁"><template #left><image src="/static/icon/menu.svg" style="width:40rpx;height:40rpx" /></template><template #right><image src="/static/icon/search.svg" style="width:40rpx;height:40rpx" /></template>
</CustomNavBar>

http://www.dtcms.com/a/549171.html

相关文章:

  • 邯郸住房及城乡建设部网站有专门做ppt的网站有哪些
  • Spring Boot3零基础教程,Lambda 表达式的使用,笔记96
  • Rust入门开发之Rust 语法中函数基本形式详解
  • 【机器学习】管道化与自动化建模
  • LangChain Few-Shot Prompt Templates(two)
  • Spring Al学习3:Prompt
  • 网站优化外链贵州互联网公司
  • 宿迁做网站哪家好做网站要注意哪些
  • 打造属于你的 Telegram 中文版:汉化方案 + @letstgbot 搜索引擎整合教程
  • web--请求响应、分层解耦
  • 做进化树的在线网站东莞软文推广
  • 从零开始的云原生之旅(八):CronJob 实战定时清理任务
  • Python自动化测试 | 快速认识并了解pytest的基本使用
  • 网站备案增加域名天津招聘网人才招聘官网
  • 有什么做外贸的好网站直播网站app下载
  • seo网站改版方案怎么写如何做网站内部优化
  • 找婚庆公司去什么网站亚马逊雨林动物大全
  • 基于百度地铁 API 的长沙地铁站点详情查询与路线导航实践
  • C# 继承
  • Ubuntu 24.04 从源码编译 dcgm-exporter
  • 【软件测试基础】详解数据库核心操作:增删改查,及测试关注点
  • 建网站服务厦门市建设路网站
  • 大模型-多模态机器学习
  • JavaSE基础——第十三章 泛型
  • 从传统到未来:Java在现代开发中的新价值与进化方向
  • 设置linux公钥,私钥登录ssh登录
  • html的网站案例wordpress文章彩色字体
  • set/map刷力扣题/(哈希表+排序类型)仿函数和捕获-两种方法解决
  • 基于单片机与 DeepSeek-OCR 的盲人辅助阅读器设计与实现
  • 淘客网站cms怎么做肥乡专业做网站