hookehuyr

feat(导航): 添加全局底部导航组件并替换各页面原有导航

将原有的分散在各页面的底部导航代码重构为可复用的indexNav组件
支持不同位置、选中状态和中心按钮样式配置
通过props控制导航行为和样式,统一管理导航逻辑
...@@ -7,6 +7,7 @@ export {} ...@@ -7,6 +7,7 @@ export {}
7 7
8 declare module 'vue' { 8 declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 + IndexNav: typeof import('./src/components/indexNav.vue')['default']
10 NutButton: typeof import('@nutui/nutui-taro')['Button'] 11 NutButton: typeof import('@nutui/nutui-taro')['Button']
11 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox'] 12 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox']
12 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup'] 13 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup']
......
1 +<template>
2 + <view class="index-nav" :class="[`is-${position}`]">
3 + <view class="nav-logo" :class="{ 'is-active': active === 'home' }" @tap="() => on_select('home')">
4 + <image class="nav-icon" :src="icons?.home" mode="aspectFit" />
5 + <text class="nav-text">首页</text>
6 + </view>
7 +
8 + <view
9 + class="nav-logo"
10 + :class="[{ 'is-active': active === 'code' }, { 'is-center-raised': center_variant === 'raised' }]"
11 + @tap="() => on_select('code')"
12 + >
13 + <image
14 + class="nav-icon"
15 + :class="{ 'nav-icon--raised': center_variant === 'raised' }"
16 + :src="icons?.code"
17 + mode="aspectFit"
18 + />
19 + <view v-if="center_variant === 'raised'" class="nav-icon-placeholder"></view>
20 + <text class="nav-text">预约码</text>
21 + </view>
22 +
23 + <view class="nav-logo" :class="{ 'is-active': active === 'me' }" @tap="() => on_select('me')">
24 + <image class="nav-icon" :src="icons?.me" mode="aspectFit" />
25 + <text class="nav-text">我的</text>
26 + </view>
27 + </view>
28 +</template>
29 +
30 +<script setup>
31 +const props = defineProps({
32 + icons: {
33 + type: Object,
34 + default: () => ({})
35 + },
36 + active: {
37 + type: String,
38 + default: ''
39 + },
40 + position: {
41 + type: String,
42 + default: 'fixed'
43 + },
44 + center_variant: {
45 + type: String,
46 + default: 'normal'
47 + },
48 + allow_active_tap: {
49 + type: Boolean,
50 + default: false
51 + }
52 +})
53 +
54 +const emit = defineEmits(['select'])
55 +
56 +const on_select = (key) => {
57 + if (!props.allow_active_tap && props.active && key === props.active) return
58 + emit('select', key)
59 +}
60 +</script>
61 +
62 +<style lang="less">
63 +.index-nav {
64 + left: 0;
65 + bottom: 0;
66 + width: 750rpx;
67 + height: 134rpx;
68 + background: #FFFFFF;
69 + box-shadow: 0 -10rpx 8rpx 0 rgba(0, 0, 0, 0.12);
70 + display: flex;
71 + align-items: center;
72 + justify-content: space-around;
73 + color: #A67939;
74 + z-index: 99;
75 +
76 + &.is-fixed {
77 + position: fixed;
78 + }
79 +
80 + &.is-absolute {
81 + position: absolute;
82 + }
83 +
84 + .nav-logo {
85 + position: relative;
86 + display: flex;
87 + flex-direction: column;
88 + align-items: center;
89 + }
90 +
91 + .nav-icon {
92 + width: 48rpx;
93 + height: 48rpx;
94 + display: block;
95 +
96 + &.nav-icon--raised {
97 + width: 130rpx;
98 + height: 130rpx;
99 + position: absolute;
100 + top: -100rpx;
101 + left: 50%;
102 + transform: translateX(-50%);
103 + }
104 + }
105 +
106 + .nav-icon-placeholder {
107 + width: 48rpx;
108 + height: 48rpx;
109 + }
110 +
111 + .nav-text {
112 + font-size: 24rpx;
113 + margin-top: 12rpx;
114 + line-height: 1;
115 + }
116 +
117 + .nav-logo.is-center-raised {
118 + .nav-text {
119 + margin-top: -10rpx;
120 + }
121 + }
122 +}
123 +</style>
1 <!-- 1 <!--
2 * @Date: 2024-01-16 10:06:47 2 * @Date: 2024-01-16 10:06:47
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-13 21:33:58 4 + * @LastEditTime: 2026-01-21 17:14:47
5 * @FilePath: /xyxBooking-weapp/src/pages/bookingCode/index.vue 5 * @FilePath: /xyxBooking-weapp/src/pages/bookingCode/index.vue
6 * @Description: 预约码页面 6 * @Description: 预约码页面
7 --> 7 -->
...@@ -15,20 +15,13 @@ ...@@ -15,20 +15,13 @@
15 <view style="height: 256rpx;"></view> 15 <view style="height: 256rpx;"></view>
16 </view> 16 </view>
17 </view> 17 </view>
18 - <view class="index-nav"> 18 + <indexNav
19 - <view class="nav-logo" @tap="toHome"> 19 + :icons="nav_icons"
20 - <image :src="icon_3" style="width: 48rpx; height: 48rpx;" /> 20 + active="code"
21 - 首页 21 + position="fixed"
22 - </view> 22 + center_variant="normal"
23 - <view class="nav-logo"> 23 + @select="on_nav_select"
24 - <image :src="icon_4" style="width: 48rpx; height: 48rpx; margin-bottom: 3rpx;" /> 24 + />
25 - 预约码
26 - </view>
27 - <view class="nav-logo" @tap="toMy">
28 - <image :src="icon_5" style="width: 48rpx; height: 48rpx;" />
29 - 我的
30 - </view>
31 - </view>
32 </view> 25 </view>
33 </template> 26 </template>
34 27
...@@ -37,6 +30,7 @@ import { ref } from 'vue' ...@@ -37,6 +30,7 @@ import { ref } from 'vue'
37 import Taro, { useDidShow } from '@tarojs/taro' 30 import Taro, { useDidShow } from '@tarojs/taro'
38 import qrCode from '@/components/qrCode'; 31 import qrCode from '@/components/qrCode';
39 import { IconFont } from '@nutui/icons-vue-taro' 32 import { IconFont } from '@nutui/icons-vue-taro'
33 +import indexNav from '@/components/indexNav.vue'
40 import icon_3 from '@/assets/images/首页01@2x.png' 34 import icon_3 from '@/assets/images/首页01@2x.png'
41 import icon_4 from '@/assets/images/二维码icon.png' 35 import icon_4 from '@/assets/images/二维码icon.png'
42 import icon_5 from '@/assets/images/我的01@2x.png' 36 import icon_5 from '@/assets/images/我的01@2x.png'
...@@ -89,6 +83,13 @@ const toHome = () => { // 跳转到首页 ...@@ -89,6 +83,13 @@ const toHome = () => { // 跳转到首页
89 }) 83 })
90 } 84 }
91 85
86 +const nav_icons = { home: icon_3, code: icon_4, me: icon_5 }
87 +
88 +const on_nav_select = (key) => {
89 + if (key === 'home') return toHome()
90 + if (key === 'me') return toMy()
91 +}
92 +
92 </script> 93 </script>
93 94
94 <style lang="less"> 95 <style lang="less">
...@@ -102,25 +103,5 @@ const toHome = () => { // 跳转到首页 ...@@ -102,25 +103,5 @@ const toHome = () => { // 跳转到首页
102 color: #A67939; 103 color: #A67939;
103 margin-top: 32rpx; 104 margin-top: 32rpx;
104 } 105 }
105 -
106 - .index-nav {
107 - position: fixed;
108 - bottom: 0;
109 - left: 0;
110 - width: 750rpx;
111 - height: 134rpx;
112 - background: #FFFFFF;
113 - box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.12);
114 - display: flex;
115 - align-items: center;
116 - justify-content: space-around;
117 - color: #A67939;
118 - .nav-logo {
119 - position: relative;
120 - display: flex;
121 - flex-direction: column;
122 - align-items: center;
123 - }
124 - }
125 } 106 }
126 </style> 107 </style>
......
...@@ -33,21 +33,13 @@ ...@@ -33,21 +33,13 @@
33 </view> 33 </view>
34 <view class="logo" :style="logo_style"></view> 34 <view class="logo" :style="logo_style"></view>
35 </view> 35 </view>
36 - <view class="index-nav"> 36 + <indexNav
37 - <view class="nav-logo"> 37 + :icons="nav_icons"
38 - <image :src="icon_3" style="width: 48rpx; height: 48rpx;" /> 38 + active="home"
39 - 首页 39 + position="absolute"
40 - </view> 40 + center_variant="raised"
41 - <view class="nav-logo" @tap="toCode"> 41 + @select="on_nav_select"
42 - <image :src="icon_4" style="width: 140rpx; height: 140rpx; position: absolute; top: -100rpx;" /> 42 + />
43 - <view style="width: 48rpx; height: 48rpx;"></view>
44 - 预约码
45 - </view>
46 - <view class="nav-logo" @tap="toMy">
47 - <image :src="icon_5" style="width: 48rpx; height: 48rpx;" />
48 - 我的
49 - </view>
50 - </view>
51 </view> 43 </view>
52 </template> 44 </template>
53 45
...@@ -58,6 +50,7 @@ import { ref, onMounted, onUnmounted, computed } from 'vue' ...@@ -58,6 +50,7 @@ import { ref, onMounted, onUnmounted, computed } from 'vue'
58 import { useGo } from '@/hooks/useGo' 50 import { useGo } from '@/hooks/useGo'
59 import { get_network_type, is_usable_network } from '@/utils/network' 51 import { get_network_type, is_usable_network } from '@/utils/network'
60 import { weak_network_text } from '@/utils/uiText' 52 import { weak_network_text } from '@/utils/uiText'
53 +import indexNav from '@/components/indexNav.vue'
61 54
62 import icon_1 from '@/assets/images/立即预约@2x.png' 55 import icon_1 from '@/assets/images/立即预约@2x.png'
63 import icon_3 from '@/assets/images/首页02@2x.png' 56 import icon_3 from '@/assets/images/首页02@2x.png'
...@@ -230,6 +223,13 @@ const toMy = () => { // 跳转到我的 ...@@ -230,6 +223,13 @@ const toMy = () => { // 跳转到我的
230 }) 223 })
231 } 224 }
232 225
226 +const nav_icons = { home: icon_3, code: icon_4, me: icon_5 }
227 +
228 +const on_nav_select = (key) => {
229 + if (key === 'code') return toCode()
230 + if (key === 'me') return toMy()
231 +}
232 +
233 useShareAppMessage(() => { 233 useShareAppMessage(() => {
234 return { 234 return {
235 title: '西园寺预约', 235 title: '西园寺预约',
...@@ -355,24 +355,5 @@ useShareAppMessage(() => { ...@@ -355,24 +355,5 @@ useShareAppMessage(() => {
355 background-position: center; 355 background-position: center;
356 } 356 }
357 } 357 }
358 - .index-nav {
359 - position: absolute;
360 - bottom: 0;
361 - left: 0;
362 - width: 750rpx;
363 - height: 134rpx;
364 - background: #FFFFFF;
365 - box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.12);
366 - display: flex;
367 - align-items: center;
368 - justify-content: space-around;
369 - color: #A67939;
370 - .nav-logo {
371 - position: relative;
372 - display: flex;
373 - flex-direction: column;
374 - align-items: center;
375 - }
376 - }
377 } 358 }
378 </style> 359 </style>
......
...@@ -9,21 +9,13 @@ ...@@ -9,21 +9,13 @@
9 <IconFont name="rect-right" size="38rpx" /> 9 <IconFont name="rect-right" size="38rpx" />
10 </view> 10 </view>
11 </view> 11 </view>
12 - <view class="index-nav"> 12 + <indexNav
13 - <view class="nav-logo" @tap="toHome"> 13 + :icons="nav_icons"
14 - <image :src="icon_3" style="width: 48rpx; height: 48rpx;" /> 14 + active="me"
15 - 首页 15 + position="fixed"
16 - </view> 16 + center_variant="raised"
17 - <view class="nav-logo" @tap="toCode"> 17 + @select="on_nav_select"
18 - <image :src="icon_4" style="width: 140rpx; height: 140rpx; position: absolute; top: -100rpx;" /> 18 + />
19 - <view style="width: 48rpx; height: 48rpx;"></view>
20 - 预约码
21 - </view>
22 - <view class="nav-logo">
23 - <image :src="icon_5" style="width: 48rpx; height: 48rpx;" />
24 - 我的
25 - </view>
26 - </view>
27 </view> 19 </view>
28 </template> 20 </template>
29 21
...@@ -32,6 +24,7 @@ import { ref } from 'vue' ...@@ -32,6 +24,7 @@ import { ref } from 'vue'
32 import Taro from '@tarojs/taro' 24 import Taro from '@tarojs/taro'
33 import { useGo } from '@/hooks/useGo' 25 import { useGo } from '@/hooks/useGo'
34 import { IconFont } from '@nutui/icons-vue-taro' 26 import { IconFont } from '@nutui/icons-vue-taro'
27 +import indexNav from '@/components/indexNav.vue'
35 import icon_3 from '@/assets/images/首页01@2x.png' 28 import icon_3 from '@/assets/images/首页01@2x.png'
36 import icon_4 from '@/assets/images/二维码icon.png' 29 import icon_4 from '@/assets/images/二维码icon.png'
37 import icon_5 from '@/assets/images/我的02@2x.png' 30 import icon_5 from '@/assets/images/我的02@2x.png'
...@@ -78,6 +71,13 @@ const toHome = () => { // 跳转到首页 ...@@ -78,6 +71,13 @@ const toHome = () => { // 跳转到首页
78 }) 71 })
79 } 72 }
80 73
74 +const nav_icons = { home: icon_3, code: icon_4, me: icon_5 }
75 +
76 +const on_nav_select = (key) => {
77 + if (key === 'home') return toHome()
78 + if (key === 'code') return toCode()
79 +}
80 +
81 const menu_list = [{ 81 const menu_list = [{
82 icon: icon_booking, 82 icon: icon_booking,
83 name: '预约记录', 83 name: '预约记录',
...@@ -114,24 +114,5 @@ const menu_list = [{ ...@@ -114,24 +114,5 @@ const menu_list = [{
114 align-items: center; 114 align-items: center;
115 } 115 }
116 } 116 }
117 - .index-nav {
118 - position: fixed;
119 - bottom: 0;
120 - left: 0;
121 - width: 750rpx;
122 - height: 134rpx;
123 - background: #FFFFFF;
124 - box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.12);
125 - display: flex;
126 - align-items: center;
127 - justify-content: space-around;
128 - color: #A67939;
129 - .nav-logo {
130 - position: relative;
131 - display: flex;
132 - flex-direction: column;
133 - align-items: center;
134 - }
135 - }
136 } 117 }
137 </style> 118 </style>
......
...@@ -26,20 +26,14 @@ ...@@ -26,20 +26,14 @@
26 </view> 26 </view>
27 </view> 27 </view>
28 <view style="height: 256rpx;"></view> 28 <view style="height: 256rpx;"></view>
29 - <view class="index-nav"> 29 + <indexNav
30 - <view class="nav-logo" @tap="toHome"> 30 + :icons="nav_icons"
31 - <image :src="icon_3" style="width: 48rpx; height: 48rpx;" /> 31 + active="me"
32 - 首页 32 + :allow_active_tap="true"
33 - </view> 33 + position="fixed"
34 - <view class="nav-logo" @tap="toCode"> 34 + center_variant="normal"
35 - <image :src="icon_4" style="width: 48rpx; height: 48rpx; margin-bottom: 3rpx;" /> 35 + @select="on_nav_select"
36 - 预约码 36 + />
37 - </view>
38 - <view class="nav-logo" @tap="toMy">
39 - <image :src="icon_5" style="width: 48rpx; height: 48rpx;" />
40 - 我的
41 - </view>
42 - </view>
43 </view> 37 </view>
44 </template> 38 </template>
45 39
...@@ -49,6 +43,7 @@ import Taro, { useDidShow } from '@tarojs/taro' ...@@ -49,6 +43,7 @@ import Taro, { useDidShow } from '@tarojs/taro'
49 import { IconFont } from '@nutui/icons-vue-taro' 43 import { IconFont } from '@nutui/icons-vue-taro'
50 import { useGo } from '@/hooks/useGo' 44 import { useGo } from '@/hooks/useGo'
51 import { personListAPI, delPersonAPI } from '@/api/index' 45 import { personListAPI, delPersonAPI } from '@/api/index'
46 +import indexNav from '@/components/indexNav.vue'
52 import icon_3 from '@/assets/images/首页01@2x.png' 47 import icon_3 from '@/assets/images/首页01@2x.png'
53 import icon_4 from '@/assets/images/二维码icon.png' 48 import icon_4 from '@/assets/images/二维码icon.png'
54 import icon_5 from '@/assets/images/我的02@2x.png' 49 import icon_5 from '@/assets/images/我的02@2x.png'
...@@ -65,6 +60,14 @@ const toMy = () => { // 跳转到我的 ...@@ -65,6 +60,14 @@ const toMy = () => { // 跳转到我的
65 go('/pages/me/index'); 60 go('/pages/me/index');
66 } 61 }
67 62
63 +const nav_icons = { home: icon_3, code: icon_4, me: icon_5 }
64 +
65 +const on_nav_select = (key) => {
66 + if (key === 'home') return toHome()
67 + if (key === 'code') return toCode()
68 + if (key === 'me') return toMy()
69 +}
70 +
68 const visitorList = ref([]); 71 const visitorList = ref([]);
69 72
70 function replaceMiddleCharacters(inputString) { 73 function replaceMiddleCharacters(inputString) {
...@@ -169,26 +172,5 @@ useDidShow(() => { ...@@ -169,26 +172,5 @@ useDidShow(() => {
169 } 172 }
170 } 173 }
171 } 174 }
172 -
173 - .index-nav {
174 - position: fixed;
175 - bottom: 0;
176 - left: 0;
177 - width: 750rpx;
178 - height: 134rpx;
179 - background: #FFFFFF;
180 - box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.12);
181 - display: flex;
182 - align-items: center;
183 - justify-content: space-around;
184 - color: #A67939;
185 - .nav-logo {
186 - position: relative;
187 - display: flex;
188 - flex-direction: column;
189 - align-items: center;
190 - font-size: 26rpx;
191 - }
192 - }
193 } 175 }
194 </style> 176 </style>
......