uniapp自定义导航栏高度自适应问题
发布时间 2024-05-11 00:24:18

  在使用 uniapp 进行小程序开发的时候,或多或少出于对样式或者功能需求,往往需要我们对小程序导航栏进行自定义操作。

一、自定义导航栏

1、效果图示

2、组件封装

  • 注意事项
  1. 导航栏组件中,我们需要在页面显示前获取高度,因此不能使用 onLoad、onMounted 等生命周期。
生命周期onLoad

  Vue3 在实现时 created 先于 onLoad 执行

  uniapp 小程序的 onLoad 生命周期在页面显示之后才会执行,而 created 生命周期在页面显示之前执行。因此,不能使用 onLoad、更不能使用 onMounted,具体查看生命周期的适配

  1. 为了方便 page 页面使用,封装组件时最好事先手动填充高度,减少影响
  • 封装示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<template>
<view class="customNavigationBar">
<view class="bar-box">
<!-- 状态栏区域 -->
<view :style="{ height: statusBarHeight + 'px' }"></view>

<!-- 导航栏区域 -->
<view class="custom-box" :style="{ height: barHeight + 'px' }">
<text>{{ title }}</text>
</view>
</view>

<!-- 仅用于填充作用 -->
<view :style="{ height: barBoxHeight + 'px' }"></view>
</view>
</template>

<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { onBeforeMount, ref } from 'vue'

const props = defineProps({
title: {
type: String,
default: '导航栏'
}
})

let statusBarHeight = ref(0)
let barHeight = ref(0)
let barBoxHeight = ref(0)

const dataInit = () => {
// 1、状态栏区域高度
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight

// 2、导航栏区域高度
// 自定义导航栏高度 = 胶囊按钮高度 + 胶囊的padding*2
const { top, height } = uni.getMenuButtonBoundingClientRect()
barHeight.value = height ? height + (top - statusBarHeight.value) * 2 : 38

// 3、当前组件高度
barBoxHeight.value = statusBarHeight.value + barHeight.value
}
dataInit()
</script>

<style lang="scss" scoped>
.customNavigationBar {
.bar-box {
position: fixed;
background-color: #ffffff;
width: 100%;
z-index: 999;

.custom-box {
// 自定义导航栏样式
text-align: center;
font-weight: bold;
font-size: 17px;
line-height: v-bind("barHeight + 'px'"); // js表达式
}
}
}
</style>

3、使用示例

  • page.json 配置
1
2
3
4
5
6
7
8
9
10
11
{
"pages": [
{
"path": "pages/home/home",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom" // 自定义导航栏
}
}
]
}
  • 页面使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<view class="home">
<customNavigationBar title="首页"></customNavigationBar>

<view class="content">
<!-- 页面内容 -->
</view>
</view>
</template>

<script setup lang="ts">
//
</script>

<style lang="scss" scoped>
.home {
//
}
</style>

二、导航栏使用问题

问题描述

  尽管我们封装了自定义导航栏组件,但是在使用过程中,某些情况下我们不得不需要知道导航栏的高度,才能正确的布局页面内容。

1、flex 布局方案

  让 content 盒子高度为 flex: 1,让其自动填充剩余空间,这是我常用的解决方案,也是最有效且简单的方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<view class="home">
<customNavigationBar title="首页"></customNavigationBar>

<view class="content">
<!-- 页面内容 -->
</view>
</view>
</template>

<script setup lang="ts">
//
</script>

<style lang="scss" scoped>
.home {
display: flex;
flex-direction: column;
min-height: 100vh;

.content {
flex: 1;

// 页面内容样式
// ...
}
}
</style>

2、获取 bar 高度方案

  但有的时候,我们需要真正的获取导航栏的高度,如:首页全屏轮播效果。

生命周期created

  uni.createSelectorQuery在页面生命周期的created阶段就可以使用。

  在页面的 created 生命周期阶段,页面已经初始化完成,可以进行 DOM 的查询和操作,随后才会进行虚拟 DOM 的渲染。

  • 注意事项
  1. 不能使用 customBarRef.value.$el.offsetHeight,因为 customBarRef 是一个响应式对象,无法直接获取到 DOM 节点。
  2. 不能使用 nextTick(()=>{}),因为 nextTick(()=>{}) 是一个异步函数,在 created 生命周期中使用会导致页面渲染延迟。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
<view class="home">
<customNavigationBar id="customBarRef" title="首页"></customNavigationBar>

<view class="content">
<view class="search-box">
<!-- search 组件 -->
</view>
<view class="notice-box">
<!-- uni-notice-bar -->
</view>
<view class="swiper-box">
<!-- swiper 组件 -->
</view>
<!-- ... -->
</view>
</view>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const customBarHeight = ref('')
const dataInit = () => {
const query = uni.createSelectorQuery().in(instance)
query
.select('#customBarRef')
.boundingClientRect((data) => {
customBarHeight.value = data.height + 'px'
})
.exec()
}
dataInit()
</script>

<style lang="scss" scoped>
.home {
display: flex;
flex-direction: column;
min-height: 100vh;

.content {
flex: 1;

.search-box {
height: 45px;
}
.notice-box {
height: 35px;
}
.swiper-box {
height: calc(100vh - 80px - v-bind(customBarHeight));
}
// ...
}
}
</style>
上一页
2024-06-11 00:39:23
下一页