feat(tabbar): 添加自定义底部导航栏组件并替换原生tabbar
移除原生tabbar配置,新增自定义TabBar组件并在各页面引入
Showing
8 changed files
with
153 additions
and
51 deletions
| ... | @@ -8,7 +8,6 @@ export {} | ... | @@ -8,7 +8,6 @@ export {} |
| 8 | declare module 'vue' { | 8 | declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] | 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] |
| 11 | - NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] | ||
| 12 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] | 11 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] |
| 13 | NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] | 12 | NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] |
| 14 | NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] | 13 | NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] |
| ... | @@ -16,5 +15,6 @@ declare module 'vue' { | ... | @@ -16,5 +15,6 @@ declare module 'vue' { |
| 16 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 15 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 17 | RouterLink: typeof import('vue-router')['RouterLink'] | 16 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 18 | RouterView: typeof import('vue-router')['RouterView'] | 17 | RouterView: typeof import('vue-router')['RouterView'] |
| 18 | + TabBar: typeof import('./src/components/TabBar.vue')['default'] | ||
| 19 | } | 19 | } |
| 20 | } | 20 | } | ... | ... |
| ... | @@ -26,42 +26,5 @@ export default { | ... | @@ -26,42 +26,5 @@ export default { |
| 26 | navigationBarTitleText: 'WeChat', | 26 | navigationBarTitleText: 'WeChat', |
| 27 | navigationBarTextStyle: 'black' | 27 | navigationBarTextStyle: 'black' |
| 28 | }, | 28 | }, |
| 29 | - tabBar: { | 29 | + |
| 30 | - color: '#6b7280', | ||
| 31 | - selectedColor: '#f97316', | ||
| 32 | - backgroundColor: '#ffffff', | ||
| 33 | - borderStyle: 'black', | ||
| 34 | - list: [ | ||
| 35 | - { | ||
| 36 | - pagePath: 'pages/index/index', | ||
| 37 | - text: '首页', | ||
| 38 | - iconPath: 'assets/images/icon/icon_home1@2x.png', | ||
| 39 | - selectedIconPath: 'assets/images/icon/icon_home2@2x.png' | ||
| 40 | - }, | ||
| 41 | - { | ||
| 42 | - pagePath: 'pages/post/index', | ||
| 43 | - text: '分类', | ||
| 44 | - iconPath: 'assets/images/icon/icon_book1@2x.png', | ||
| 45 | - selectedIconPath: 'assets/images/icon/icon_book2@2x.png' | ||
| 46 | - }, | ||
| 47 | - { | ||
| 48 | - pagePath: 'pages/sell/index', | ||
| 49 | - text: '我要卖车', | ||
| 50 | - iconPath: 'assets/images/icon/icon_server1.png', | ||
| 51 | - selectedIconPath: 'assets/images/icon/icon_server2.png' | ||
| 52 | - }, | ||
| 53 | - { | ||
| 54 | - pagePath: 'pages/messages/index', | ||
| 55 | - text: '消息', | ||
| 56 | - iconPath: 'assets/images/icon/icon_book1@2x.png', | ||
| 57 | - selectedIconPath: 'assets/images/icon/icon_book2@2x.png' | ||
| 58 | - }, | ||
| 59 | - { | ||
| 60 | - pagePath: 'pages/profile/index', | ||
| 61 | - text: '我的', | ||
| 62 | - iconPath: 'assets/images/icon/icon_my1@2x.png', | ||
| 63 | - selectedIconPath: 'assets/images/icon/icon_my2@2x.png' | ||
| 64 | - } | ||
| 65 | - ] | ||
| 66 | - } | ||
| 67 | } | 30 | } | ... | ... |
src/components/TabBar.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="fixed bottom-0 w-full max-w-md mx-auto z-50"> | ||
| 3 | + <div class="backdrop-blur-md bg-white/70 border-t border-gray-200 px-4 py-2"> | ||
| 4 | + <div class="flex justify-around items-center"> | ||
| 5 | + <!-- 首页 --> | ||
| 6 | + <view | ||
| 7 | + @click="navigateTo('/pages/index/index')" | ||
| 8 | + :class="getTabClass('index')" | ||
| 9 | + > | ||
| 10 | + <Home size="20" :color="getIconColor('index')" /> | ||
| 11 | + <span class="text-xs mt-1">首页</span> | ||
| 12 | + </view> | ||
| 13 | + | ||
| 14 | + <!-- 分类 --> | ||
| 15 | + <view | ||
| 16 | + @click="navigateTo('/pages/post/index')" | ||
| 17 | + :class="getTabClass('post')" | ||
| 18 | + > | ||
| 19 | + <Category size="20" :color="getIconColor('post')" /> | ||
| 20 | + <span class="text-xs mt-1">分类</span> | ||
| 21 | + </view> | ||
| 22 | + | ||
| 23 | + <!-- 我要卖车 --> | ||
| 24 | + <div class="relative -mt-5"> | ||
| 25 | + <view | ||
| 26 | + @click="navigateTo('/pages/sell/index')" | ||
| 27 | + class="bg-orange-500 rounded-full p-3 text-white shadow-lg" | ||
| 28 | + > | ||
| 29 | + <span class="text-sm font-medium">我要卖车</span> | ||
| 30 | + </view> | ||
| 31 | + </div> | ||
| 32 | + | ||
| 33 | + <!-- 消息 --> | ||
| 34 | + <view | ||
| 35 | + @click="navigateTo('/pages/messages/index')" | ||
| 36 | + :class="getTabClass('messages')" | ||
| 37 | + > | ||
| 38 | + <Comment size="20" :color="getIconColor('messages')" /> | ||
| 39 | + <span class="text-xs mt-1">消息</span> | ||
| 40 | + </view> | ||
| 41 | + | ||
| 42 | + <!-- 我的 --> | ||
| 43 | + <view | ||
| 44 | + @click="navigateTo('/pages/profile/index')" | ||
| 45 | + :class="getTabClass('profile')" | ||
| 46 | + > | ||
| 47 | + <My size="20" :color="getIconColor('profile')" /> | ||
| 48 | + <span class="text-xs mt-1">我的</span> | ||
| 49 | + </view> | ||
| 50 | + </div> | ||
| 51 | + </div> | ||
| 52 | + </div> | ||
| 53 | +</template> | ||
| 54 | + | ||
| 55 | +<script setup> | ||
| 56 | +import { ref, onMounted } from 'vue' | ||
| 57 | +import Taro from '@tarojs/taro' | ||
| 58 | +import { Home, Category, Comment, My } from '@nutui/icons-vue-taro' | ||
| 59 | + | ||
| 60 | +// 当前激活的tab | ||
| 61 | +const activeTab = ref('') | ||
| 62 | + | ||
| 63 | +/** | ||
| 64 | + * 获取当前页面路径并设置激活状态 | ||
| 65 | + */ | ||
| 66 | +const getCurrentPage = () => { | ||
| 67 | + const pages = Taro.getCurrentPages() | ||
| 68 | + if (pages.length > 0) { | ||
| 69 | + const currentPage = pages[pages.length - 1] | ||
| 70 | + const route = currentPage.route | ||
| 71 | + | ||
| 72 | + if (route.includes('index/index')) { | ||
| 73 | + activeTab.value = 'index' | ||
| 74 | + } else if (route.includes('post/index')) { | ||
| 75 | + activeTab.value = 'post' | ||
| 76 | + } else if (route.includes('sell/index')) { | ||
| 77 | + activeTab.value = 'sell' | ||
| 78 | + } else if (route.includes('messages/index')) { | ||
| 79 | + activeTab.value = 'messages' | ||
| 80 | + } else if (route.includes('profile/index')) { | ||
| 81 | + activeTab.value = 'profile' | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +/** | ||
| 87 | + * 导航到指定页面 | ||
| 88 | + * @param {string} url - 页面路径 | ||
| 89 | + */ | ||
| 90 | +const navigateTo = (url) => { | ||
| 91 | + Taro.redirectTo({ | ||
| 92 | + url: url | ||
| 93 | + }) | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +/** | ||
| 97 | + * 获取tab按钮的样式类 | ||
| 98 | + * @param {string} tab - tab标识 | ||
| 99 | + * @returns {string} 样式类名 | ||
| 100 | + */ | ||
| 101 | +const getTabClass = (tab) => { | ||
| 102 | + const baseClass = 'flex flex-col items-center p-2' | ||
| 103 | + const activeClass = activeTab.value === tab ? 'text-orange-500' : 'text-gray-500' | ||
| 104 | + return `${baseClass} ${activeClass}` | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +/** | ||
| 108 | + * 获取图标颜色 | ||
| 109 | + * @param {string} tab - tab标识 | ||
| 110 | + * @returns {string} 颜色值 | ||
| 111 | + */ | ||
| 112 | +const getIconColor = (tab) => { | ||
| 113 | + return activeTab.value === tab ? '#f97316' : '#6b7280' | ||
| 114 | +} | ||
| 115 | + | ||
| 116 | +onMounted(() => { | ||
| 117 | + getCurrentPage() | ||
| 118 | +}) | ||
| 119 | +</script> | ||
| 120 | + | ||
| 121 | +<style lang="less" scoped> | ||
| 122 | +/* 确保底部导航栏在最上层 */ | ||
| 123 | +.z-50 { | ||
| 124 | + z-index: 50; | ||
| 125 | +} | ||
| 126 | +</style> |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-06-28 10:33:00 | 2 | * @Date: 2025-06-28 10:33:00 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-01 21:32:07 | 4 | + * @LastEditTime: 2025-07-01 21:50:54 |
| 5 | * @FilePath: /jgdl/src/pages/index/index.vue | 5 | * @FilePath: /jgdl/src/pages/index/index.vue |
| 6 | * @Description: 捡个电驴首页 | 6 | * @Description: 捡个电驴首页 |
| 7 | --> | 7 | --> |
| ... | @@ -143,6 +143,9 @@ | ... | @@ -143,6 +143,9 @@ |
| 143 | </view> | 143 | </view> |
| 144 | </view> | 144 | </view> |
| 145 | </view> | 145 | </view> |
| 146 | + | ||
| 147 | + <!-- 自定义TabBar --> | ||
| 148 | + <TabBar /> | ||
| 146 | </view> | 149 | </view> |
| 147 | </template> | 150 | </template> |
| 148 | 151 | ||
| ... | @@ -151,7 +154,8 @@ import Taro from '@tarojs/taro' | ... | @@ -151,7 +154,8 @@ import Taro from '@tarojs/taro' |
| 151 | // import '@tarojs/taro/html.css' 和 nutui组件居然有冲突? | 154 | // import '@tarojs/taro/html.css' 和 nutui组件居然有冲突? |
| 152 | import { ref, onMounted } from 'vue' | 155 | import { ref, onMounted } from 'vue' |
| 153 | import { useDidShow, useReady } from '@tarojs/taro' | 156 | import { useDidShow, useReady } from '@tarojs/taro' |
| 154 | -import { Clock, Star, Service, Right, Heart1, Addfollow, HeartFill, Check, Search2, Shop } from '@nutui/icons-vue-taro' | 157 | +import { Clock, Star, Right, Addfollow, HeartFill, Check, Search2, Shop } from '@nutui/icons-vue-taro' |
| 158 | +import TabBar from '@/components/TabBar.vue' | ||
| 155 | import "./index.less"; | 159 | import "./index.less"; |
| 156 | 160 | ||
| 157 | // 响应式数据 | 161 | // 响应式数据 | ... | ... |
| ... | @@ -58,13 +58,17 @@ | ... | @@ -58,13 +58,17 @@ |
| 58 | <view class="floating-btn" @click="onNewMessage"> | 58 | <view class="floating-btn" @click="onNewMessage"> |
| 59 | <Plus size="24" color="#ffffff" /> | 59 | <Plus size="24" color="#ffffff" /> |
| 60 | </view> | 60 | </view> |
| 61 | + | ||
| 62 | + <!-- 自定义TabBar --> | ||
| 63 | + <TabBar /> | ||
| 61 | </view> | 64 | </view> |
| 62 | </template> | 65 | </template> |
| 63 | 66 | ||
| 64 | <script setup> | 67 | <script setup> |
| 65 | import { ref, computed } from 'vue' | 68 | import { ref, computed } from 'vue' |
| 66 | -import { Search, Message, Plus } from '@nutui/icons-vue-taro' | 69 | +import { Search, Message, Plus, Image } from '@nutui/icons-vue-taro' |
| 67 | import Taro from '@tarojs/taro' | 70 | import Taro from '@tarojs/taro' |
| 71 | +import TabBar from '@/components/TabBar.vue' | ||
| 68 | 72 | ||
| 69 | // 响应式数据 | 73 | // 响应式数据 |
| 70 | const searchValue = ref('') | 74 | const searchValue = ref('') | ... | ... |
| ... | @@ -100,11 +100,16 @@ | ... | @@ -100,11 +100,16 @@ |
| 100 | </view> | 100 | </view> |
| 101 | </view> | 101 | </view> |
| 102 | </view> | 102 | </view> |
| 103 | + | ||
| 104 | + <!-- 自定义TabBar --> | ||
| 105 | + <TabBar /> | ||
| 103 | </template> | 106 | </template> |
| 104 | 107 | ||
| 105 | <script setup> | 108 | <script setup> |
| 106 | import { ref } from 'vue' | 109 | import { ref } from 'vue' |
| 110 | +import Taro from '@tarojs/taro' | ||
| 107 | import { Search, Right, Cart, Star, Cart2, Category, Heart } from '@nutui/icons-vue-taro' | 111 | import { Search, Right, Cart, Star, Cart2, Category, Heart } from '@nutui/icons-vue-taro' |
| 112 | +import TabBar from '@/components/TabBar.vue' | ||
| 108 | 113 | ||
| 109 | // 响应式数据 | 114 | // 响应式数据 |
| 110 | const searchValue = ref('') | 115 | const searchValue = ref('') |
| ... | @@ -187,18 +192,10 @@ const onProductClick = () => { | ... | @@ -187,18 +192,10 @@ const onProductClick = () => { |
| 187 | }) | 192 | }) |
| 188 | } | 193 | } |
| 189 | 194 | ||
| 190 | -const onSearch = () => { | ||
| 191 | - Taro.showToast({ | ||
| 192 | - title: '搜索功能', | ||
| 193 | - icon: 'none' | ||
| 194 | - }) | ||
| 195 | -} | ||
| 196 | - | ||
| 197 | /** | 195 | /** |
| 198 | * 查看更多点击事件 | 196 | * 查看更多点击事件 |
| 199 | - * @param {string} type - 类型(hot/latest) | ||
| 200 | */ | 197 | */ |
| 201 | -const onViewMore = (type) => { | 198 | +const onViewMore = () => { |
| 202 | // 跳转到列表页面 | 199 | // 跳转到列表页面 |
| 203 | } | 200 | } |
| 204 | </script> | 201 | </script> | ... | ... |
| ... | @@ -120,6 +120,9 @@ | ... | @@ -120,6 +120,9 @@ |
| 120 | <view class="logout-section"> | 120 | <view class="logout-section"> |
| 121 | <button class="logout-btn" @click="onLogout">退出登录</button> | 121 | <button class="logout-btn" @click="onLogout">退出登录</button> |
| 122 | </view> | 122 | </view> |
| 123 | + | ||
| 124 | + <!-- 自定义TabBar --> | ||
| 125 | + <TabBar /> | ||
| 123 | </view> | 126 | </view> |
| 124 | </template> | 127 | </template> |
| 125 | 128 | ||
| ... | @@ -130,6 +133,7 @@ import { | ... | @@ -130,6 +133,7 @@ import { |
| 130 | Voice, Message, Tips, Setting | 133 | Voice, Message, Tips, Setting |
| 131 | } from '@nutui/icons-vue-taro' | 134 | } from '@nutui/icons-vue-taro' |
| 132 | import Taro from '@tarojs/taro' | 135 | import Taro from '@tarojs/taro' |
| 136 | +import TabBar from '@/components/TabBar.vue' | ||
| 133 | 137 | ||
| 134 | // 用户信息 | 138 | // 用户信息 |
| 135 | const userInfo = ref({ | 139 | const userInfo = ref({ | ... | ... |
| ... | @@ -176,6 +176,9 @@ | ... | @@ -176,6 +176,9 @@ |
| 176 | <button class="preview-btn" @click="onPreview">预览</button> | 176 | <button class="preview-btn" @click="onPreview">预览</button> |
| 177 | <button class="publish-btn" @click="onPublish">发布车辆</button> | 177 | <button class="publish-btn" @click="onPublish">发布车辆</button> |
| 178 | </view> | 178 | </view> |
| 179 | + | ||
| 180 | + <!-- 自定义TabBar --> | ||
| 181 | + <TabBar /> | ||
| 179 | </view> | 182 | </view> |
| 180 | </template> | 183 | </template> |
| 181 | 184 | ||
| ... | @@ -183,6 +186,7 @@ | ... | @@ -183,6 +186,7 @@ |
| 183 | import { ref, reactive } from 'vue' | 186 | import { ref, reactive } from 'vue' |
| 184 | import { Close, Plus, Right } from '@nutui/icons-vue-taro' | 187 | import { Close, Plus, Right } from '@nutui/icons-vue-taro' |
| 185 | import Taro from '@tarojs/taro' | 188 | import Taro from '@tarojs/taro' |
| 189 | +import TabBar from '@/components/TabBar.vue' | ||
| 186 | 190 | ||
| 187 | // 响应式数据 | 191 | // 响应式数据 |
| 188 | const vehicleImages = ref([]) | 192 | const vehicleImages = ref([]) | ... | ... |
-
Please register or login to post a comment