uniapp中自定义导航栏

news2025/2/27 17:34:19

相信很多小伙伴在使用uniapp进行多端开发的时候呢,在面对一些奇葩的业务需求的时候,uniapp给我们提供的默认导航栏已经不能满足我们的业务需求了,这个时候就需要我们自己自定义导航栏使用啦。

当然uniapp也给我们提供了很多的自定义导航栏的插件供大家使用,今天也给大家分享一个我自己写的导航栏啦,希望大家多多指点

首先我们在自定义导航栏的时候,我们需要知道头部的导航栏有哪几部分组成,那么我们以微信小程序为例

可以看到在微信小程序中,我们的头部导航栏其实受到右上角胶囊的限制比较大,这个时候我们自定义的导航栏,需要做到标题于胶囊水平对齐,那其实这个时候整个头部其实主要又:状态栏的高度+标题栏的高度组成。

状态栏的高度我们可以通过uni.getSystemInfoSync().statusBarHeight来获取。

那么标题栏的高度我们怎么获取呢?

其实要想定义标题栏的高度,我们需要知道这个胶囊的位置,在小程序中我们可以使用wx.getMenuButtonBoundingClientRect()获取关于胶囊的信息

获取到的胶囊的top,left,right分别对应胶囊的上边界,左边界,右边界相对于屏幕左上角的起点的位置,所以我们是不是可以用(胶囊上边界距离顶部的距离 - 状态栏的高度)*2+胶囊的高度,就是标题栏的高度呢?然后再在标题栏里面添加一个文本区让他的高度等于胶囊的高度,实现flex布局的上下居中是不是就搞定了呢?

以上呢其实针对小程序平台的导航栏讲解,那么既然使用uniapp,就会考虑到多端情况

那么其实我们使用uniapp获取到的状态栏在h5,小程序和app原生都是有效的,h5网页中一般我们都是直接采用浏览器内核给我们内置的网页导航栏,就是一个头部,没有过多的要求,而且浏览器不同,给我们提供的头部导航也不一样。

而对于app端,我们没有了像微信小程序中那种让人心烦的胶囊之后,我们只需要知道状态栏的高度,然后加上自己业务需求的标题栏样式和标题栏高度就行啦

所以我们在进行自定义导航栏封装的时候就要对代码进行条件编译啦。那么我这里呢是把微信小程序做了单独的处理,微信小程序之外的平台看作是统一状态

献上源码:

首先我们把获取设备信息的代码封装到一个统一的js文件里面,这样方便我们在组件中获取也方便我们在页面中获取。

/**
 * 此js文件管理关于当前设备的机型系统信息
 */
const systemInfo = 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
	// console.log(windowHeight,'哈哈哈哈哈');
	
	/****************** 微信小程序头部胶囊信息 ********************/
	// #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
}

export {
	systemInfo
}

然后我们定义一个导航栏组件

/*
* 注意:
* 1、在传入宽度或者高度时,如果是Number数据,传入的值为px大小,无需带单位,组件自动计算
* 2、在使用此导航栏时,建议传入UI规定的导航栏高度,此高度只针对除微信小程序的其他平台有效,微信小程序的导航栏高度,组件自计算
*/
<template>
	<view>
		<!-- 微信小程序头部导航栏 -->
		<!-- #ifdef MP-WEIXIN -->
		<view class="wx-head-mod" :style="{height:navHeight+'rpx',backgroundColor:navBackgroundColor}">
			<view class="wx-head-mod-nav" :style="{height:navigationBarHeight+'rpx',top:statusBarHeight+'rpx'}">
				<view class="wx-head-mod-nav-content"
					:style="{height:customHeight+'rpx',justifyContent:textAlign === 'center'?'center':'left'}">
					<!-- 文本区 -->
					<view class="wx-head-mod-nav-content-mian"
						:style="{width:navTextWidth,lineHeight:customHeight + 'rpx',paddingLeft:textPaddingLeft*scaleFactor+'rpx',fontSize:fontSize*scaleFactor+'rpx',fontWeight:fontWeight,color:titleColor}">
						{{textContent}}
					</view>
					<!-- 返回按钮 -->
					<view class="wx-head-mod-nav-content-back" :style="{display:isBackShow?'flex':'none'}"
						@click="backEvent">
						<view class="wx-head-mod-nav-content-back-img"
							:style="{width:backImageWidth*scaleFactor+'rpx',height:backImageHeight*scaleFactor+'rpx'}">
							<image :src="backImageUrl" mode="" style="width: 100%;height: 100%;"></image>
						</view>
					</view>
				</view>
			</view>
		</view>
		<!-- #endif -->

		<!-- 除微信小程序之外的其他设备 -->
		<!-- #ifndef MP-WEIXIN -->
		<view class="other-head-mod"
			:style="{height:navHeightValue*scaleFactor+statusBarHeight+'rpx',backgroundColor:navBackgroundColor}">
			<view class="other-head-mod-mian"
				:style="{height:navHeightValue*scaleFactor+'rpx',justifyContent:textAlign === 'center'?'center':'left'}">
				<!-- 返回按钮 -->
				<view class="other-head-mod-mian-back" v-show="isBackShow" @click="backEvent">
					<view class="other-head-mod-mian-back-img"
						:style="{width:backImageWidth*scaleFactor+'rpx',height:backImageHeight*scaleFactor+'rpx'}">
						<image :src="backImageUrl" mode="" style="width: 100%;height: 100%;"></image>
					</view>
				</view>
				<!-- 标题 -->
				<view class="other-head-mod-mian-title" :style="{width:windowWidth - 184+'rpx',lineHeight:navHeightValue*scaleFactor+'rpx',
					paddingLeft:textPaddingLeft*scaleFactor+'rpx',fontSize:fontSize*scaleFactor+'rpx',
					fontWeight:fontWeight,color:titleColor}">
					{{textContent}}
				</view>
			</view>
		</view>
		<!-- #endif -->
	</view>
</template>

<script>
	const app = getApp()
	import {systemInfo} from '@/common/system-info.js'
	export default {
		name: "HeadView",
		props: {
			// 文本区域位置 left:左  center:中  
			textAlign: {
				type: String,
				default: 'center'
			},
			// 文本区内容
			textContent: {
				type: String,
				default: '哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈就啊哈哈好借好还'
			},
			// 文本区离左边的距离
			textPaddingLeft: {
				type: Number,
				default: 16
			},
			// 是否需要返回按钮
			isBackShow: {
				type: Boolean,
				default: true
			},
			// 文本区字体大小
			fontSize: {
				type: Number,
				default: 20 //px
			},
			// 文本区字体粗细
			fontWeight: {
				type: Number,
				default: 700
			},
			// 文本区返回按钮图片宽
			backImageWidth: {
				type: Number,
				default: 12 //px
			},
			// 文本区返回按钮图片高
			backImageHeight: {
				type: Number,
				default: 24 //px
			},
			// 返回按钮图标路径
			backImageUrl: {
				type: String,
				default: '/static/backImage.svg'
			},
			// 导航栏整体背景颜色
			navBackgroundColor: {
				type: String,
				default: '#2476F9'
			},
			// 标题字体颜色
			titleColor: {
				type: String,
				default: '#ffffff',
			},

			/******** h5端,app端需要传入自定义导航栏高度 *******/
			navHeightValue: {
				type: Number,
				default: 44 //px
			}
		},
		computed: {
			// 文本区宽度
			navTextWidth() {
				if (this.textAlign === 'center') {
					return (this.windowWidth - (this.windowWidth - this.menubarLeft) * 2) + 'rpx'
				} else {
					return this.menubarLeft + 'rpx'
				}
			},
			// 文本区paddingLeft
			textPaddingleft() {
				if (this.textAlign === 'center') {
					return '0'
				} else {
					return this.textPaddingLeft + 'rpx'
				}
			}
		},
		data() {
			return {
				statusBarHeight: app.globalData.statusBarHeight, //状态栏高度
				navHeight: app.globalData.navHeight, //头部导航栏总体高度
				navigationBarHeight: app.globalData.navigationBarHeight, //导航栏高度
				customHeight: app.globalData.customHeight, //胶囊高度
				scaleFactor: app.globalData.scaleFactor, //比例系数
				menubarLeft: app.globalData.menubarLeft, //胶囊定位的左边left
				windowWidth: app.globalData.windowWidth * app.globalData.scaleFactor
			};
		},
		methods: {
			backEvent() {
				uni.navigateBack({
					delta: 1
				})
			}
		},
		created() {
			/* 获取设备信息 */
			const SystemInfomations = systemInfo()
			/* 通用平台 */
			this.statusBarHeight = SystemInfomations.statusBarHeight //状态栏高度
			this.scaleFactor = SystemInfomations.scaleFactor //比例系数
			this.windowWidth = SystemInfomations.windowWidth //当前设备的屏幕宽度
			/* 微信小程序平台 */
			// #ifdef MP-WEIXIN
			this.navHeight = SystemInfomations.navHeight + SystemInfomations.statusBarHeight //头部导航栏总高度
			this.navigationBarHeight = SystemInfomations.navHeight //头部导航栏高度
			this.customHeight = SystemInfomations.menuButtonHeight //胶囊高度
			this.menubarLeft = SystemInfomations.menuButtonLeft //胶囊左边界距离左上角的距离
			// #endif
			
		}
	}
</script>

<style>
	/* #ifdef MP-WEIXIN */
	.wx-head-mod {
		box-sizing: border-box;
		width: 100%;
		position: fixed;
		top: 0;
		left: 0;
	}

	.wx-head-mod-nav {
		box-sizing: border-box;
		width: 100%;
		position: absolute;
		left: 0;
		display: flex;
		justify-content: center;
		align-items: center;

	}

	.wx-head-mod-nav-content {
		box-sizing: border-box;
		width: 100%;
		display: flex;
		justify-content: left;
		align-items: center;
		position: relative;
	}

	/* 文本区 */
	.wx-head-mod-nav-content-mian {
		box-sizing: border-box;
		height: 100%;
		white-space: nowrap;
		text-overflow: ellipsis;
		overflow: hidden;
	}

	/* 返回按钮 */
	.wx-head-mod-nav-content-back {
		box-sizing: border-box;
		width: 60rpx;
		height: 100%;
		/* background-color: aqua; */
		position: absolute;
		top: 0;
		left: 32rpx;
		display: flex;
		align-items: center;
		justify-content: left;
	}

	.wx-head-mod-nav-content-back-img {
		box-sizing: border-box;
	}

	/* #endif */

	/* #ifndef MP-WEIXIN */
	.other-head-mod {
		box-sizing: border-box;
		width: 100%;
		position: fixed;
		top: 0;
		left: 0;
	}

	.other-head-mod-mian {
		box-sizing: border-box;
		width: 100%;
		display: flex;
		align-items: center;
		justify-content: left;
		position: absolute;
		left: 0;
		bottom: 0;
	}

	/* 返回按钮 */
	.other-head-mod-mian-back {
		box-sizing: border-box;
		height: 100%;
		width: 60rpx;
		position: absolute;
		left: 32rpx;
		top: 0;
		display: flex;
		align-items: center;
	}

	/* 标题 */
	.other-head-mod-mian-title {
		box-sizing: border-box;
		height: 100%;
		white-space: nowrap;
		text-overflow: ellipsis;
		overflow: hidden;
	}

	/* #endif */
</style>

组件使用:

引入组件:

import HeadNav from '@/components/HeadNav.vue'

组册组件:

components:{
			HeadNav
		},
<template>
	<view class="content">
		<head-nav></head-nav>
		<view class="content-main"></view>
	</view>
</template>

 效果图:

微信小程序:

h5:

app:

 

 在项目里面没有针对h5时候需要导航栏做特别的限制,如果实际开发中在h5端不需要此导航栏,请在模版上面针对h5页面加入条件编译即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405164.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开箱即用,这些 Vue3 后台管理系统模板绝对让你爽歪歪!

原文链接&#xff1a;Vue3 后台管理系统模板推荐。 之前写了一篇关于 Vue2 的后台管理系统模板的推荐&#xff0c;详情请见 Vue后台管理系统模板推荐。 Vue3 在今年2月份已成为新的默认版本&#xff0c;本文收集了一些 Vue3 的后台管理系统模板&#xff0c;分享给在座的仌 &am…

web前端面试题(必背面试题)

必背面试题-手写题 前端面试&#xff08;手写题&#xff09;_Z_Xshan的博客-CSDN博客 css系列 面试官&#xff1a;说说你对盒子模型的理解 一、是什么 所有元素都可以有像盒子一样的平面空间和外形 一个盒子由四部分组成&#xff1a;context ,padding,margin,border con…

Django web开发(一) - 前端

文章目录前端开发1.快速开发网站2.标签2.1 编码2.2 title2.3 标题2.4 div和span2.5 超链接2.6 图片小结标签的嵌套2.7 列表2.8 表格2.9 input系列2.10 下拉框2.11 多行文本用户注册案例: 用户注册GET 方式POST 方式表单数据提交优化3.CSS样式3.1 快速上手3.2 CSS应用方式1. 在标…

小程序生命周期

小程序的生命周期说白了就是指程序从创建、到开始、暂停、唤起、停止、卸载的过程。 我们大概从三个角度看一下小程序的生命周期。 &#xff08;1&#xff09;&#xff1a;应用生命周期 &#xff08;2&#xff09;&#xff1a;页面生命周期 &#xff08;3&#xff09;&…

Threejs入门教程

一、本地搭建Threejs官方文档网站 1.官网地址&#xff1a;https://github.com/mrdoob/three.js 下载压缩包并解压或使用git clone 若github过慢&#xff0c;则使用gitee对应网址&#xff1a;three.js: mrdoob/three.js 同步库 2.目录解析 3.启动方式 在three.js项目根目录下…

Vue中created和mounted详解

目录 一、生命周期概念 二、浏览器渲染过程 三、生命周期中的浏览器渲染 beforeCreate阶段 created阶段 beforeMount阶段 mounted阶段 四、使用场景 五、常见相关问题 一些页面跳转后, 一些基础数据接口没有重新请求 一、生命周期概念 通俗地讲&#xff0c;生命周期即Vue实例或…

vite.config.js详细配置。

Vue3vite vite和webpack区别&#xff1f; 1.vite服务器启动速度比webpack快&#xff0c;由于vite启动的时候不需要打包&#xff0c;也就无需分析模块依赖、编译&#xff0c;所以启动速度非常快。当浏览器请求需要的模块时&#xff0c;再对模块进行编译&#xff0c;这种按需动态…

Vue-cli(vue脚手架)上万字总结,超详细教程

1、创建Vue脚手架 1.1、首先系统需要全局安装Vue脚手架 npm install -g vue/cli 1.2、创建Vue脚手架工程 进入你想创建vue脚手架的目录&#xff0c;然后输入命令 vue create xxx项目名 需要注意的是工程名字不能大写&#xff0c;这里我们选择选择Vue2&#xff0c;敲下回车&am…

Java实现Token登录验证(基于JWT的token认证实现)

文章目录 一、JWT是什么&#xff1f;二、使用步骤 1.项目结构2.相关依赖3.数据库4.相关代码 三、测试结果 一、JWT是什么&#xff1f; 在介绍JWT之前&#xff0c;我们先来回顾一下利用token进行用户身份验证的流程&#xff1a; 1、客户端使用用户名和密码请求登录 2、服务端…

【微信小程序】view和scroll-view组件的基本使用

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;微信小程序 &#x1f4ac;个人格言&#xff1a;但行好事&#xff0c;莫问前程 view和scroll-vie…

移动端适配详解 , 给你解决适配烦恼

试想一下&#xff0c;如果我们只能开发web端&#xff0c;那么移动端的网友由谁来做&#xff01;那也太悲惨了 所以&#xff0c;这里说的就是如何开发页面到移动端&#xff0c;适配各个手机型号&#xff0c;让页面在手机上跑起来&#xff5e; 目录 理解些许概念 1. 开发的种…

Vue3新特性——Composition API详解

文章目录一、 Vue3快速入门1. Vue3 带来了什么2. Vue3工程的创建2.1 使用vue-cli创建2.2 使用vite创建2.2.1 是什么2.2.2 vite的优势2.2.3 使用步骤3. vue3项目结构的分析3.1 vue-cli 项目结构4. vue3中的开发者工具4.1 在线安装4.2 离线安装二、常用Composition API1. setup2.…

Vue3获取DOM、操作组件

文章目录&#x1f31f; 写在前面&#x1f31f; Vue2 ref 的使用&#x1f31f; Vue3获取DOM&#x1f31f; Vue3操作组件&#x1f31f; 写在最后&#x1f31f; 写在前面 专栏介绍&#xff1a; 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 Vue…

若依框架前端Vue项目分析实战

说明 前面讲解了vue2的单点知识&#xff0c;下面用若依提供的vue项目&#xff0c;实战分析一下&#xff0c;拿到一个vue项目&#xff0c;如何进行分析并进行二次开发。 一、public/index.html与main.js和App.vue三者的关系 vue项目是单界面应用&#xff0c;所有的界面将在pu…

VSCode 入门操作大全 + 实用插件推荐【零基础专属详细教程】

&#x1f4c0; 前言&#xff1a; &#x1f3ab; 选择一个好的开发工具很重要&#xff0c;很多刚学编程的小伙伴在 webstorm 和 vscode 上很难抉择&#xff0c;我个人更喜欢使用 vscode&#xff0c;因为其有着简洁的操作风格和丰富的人性化的各种功能&#xff0c;这篇文章带给大…

2022年前端Vue常见面试题大全(三万长文)持续更新...

目录 1.Vue和React有什么不同&#xff1f;使用场景分别是什么&#xff1f; 2.axios是什么&#xff1f;怎么使用它&#xff0c;怎么解决跨域&#xff1f; 3.说说Vue&#xff0c;React&#xff0c;angularjs&#xff0c;jquery的区别 4.什么阶段&#xff08;生命周期&#xff…

2022最新版40个前端练手项目【附视频+源码】

不管学习哪门语言都希望能做出实际的东西来&#xff0c;这个实际的东西当然就是项目啦&#xff0c; 不用多 说&#xff0c;大家都知道学编程语言一定要做项目才行。 本次给到大家的是40个前端实战练手项目(附源码和视频讲解)&#xff0c;希望对大家有一定的帮助&#xff0c;激…

企微获取用户敏感数据

1、企微配置可信域名 2、企微获取成员userID 3、企微获取用户敏感数据 文章目录一、简介1、企微数据安全更新2、身份验证方式2.1 网页授权登录(企微内部)2.2 扫描授权登录(浏览器)二、企微应用配置1、企微配置可信域名2、企微授权登录3、企微可信IP三、网页授权登录方式(企微)1…

Vue2 大型项目升级 Vue3 详细经验总结

前言 前段时间&#xff0c;公司准备在现有的 Vue2 项目中做一个聊天系统&#xff0c;但考虑开发聊天系统的周期并不短&#xff0c;客户又急需。于是准备对接腾讯的 IM 组件&#xff0c;来实现。 不知道的这里贴个官网&#xff1a; IM TUIKit 官方文档 对于 TUIKit&#xff0…

【axios】axios的基本使用

axios是一个专注于网络请求的库。 不同于jquery&#xff0c;功能复杂&#xff0c;既可以操作dom&#xff0c;又可以做动画&#xff0c;还可以发ajax请求。axios是一个专注于网络请求的库。 一、基本使用 1.导入库文件 在js中导入axios的库文件后&#xff0c;会直接在全局挂载…