feat(tabbar): 实现新的底部导航栏布局和功能

- 将原有tabbar组件重构为layout布局方式
- 新增tabbar store管理导航项状态和路由
- 为首页和关于页添加tabbar布局配置
- 移除旧的tabbar组件实现
- 添加tabbar路由跳转功能
- 更新类型定义以支持新组件
```

这个提交消息:
1. 使用feat类型,因为这是新增功能
2. 添加了scope(tabbar)明确修改范围
3. 简明描述了主要变更内容
4. 使用中文符合要求
5. 保持了50字符以内的描述行
6. 在正文中列出了主要变更点而不重复描述
This commit is contained in:
feige996 2025-05-27 00:21:37 +08:00
parent e123a5cb1b
commit 27f23173fd
7 changed files with 90 additions and 58 deletions

View File

@ -1,56 +0,0 @@
<template>
<view class="tabbar-box">
<view class="items" v-for="(item, index) in tabItems" :key="index" @click="toPage(item.url)">
<wd-icon :name="item.icon" size="22px"></wd-icon>
<text>{{ item.title }}</text>
</view>
</view>
</template>
<script lang="ts" setup>
defineProps({
tabItems: {
type: Array,
required: true,
validator(value) {
return value.every(
(item) =>
Object.prototype.hasOwnProperty.call(item, 'url') &&
Object.prototype.hasOwnProperty.call(item, 'icon') &&
Object.prototype.hasOwnProperty.call(item, 'title'),
)
},
},
})
const toPage = (url: string) => {
uni.switchTab({ url }) // tabBarURL
}
onLoad(() => {
uni.hideTabBar()
})
</script>
<style lang="scss" scoped>
.tabbar-box {
position: fixed;
bottom: 0;
left: 0;
z-index: 996;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 100rpx;
border-top: 1rpx solid #f2f2f2;
}
.items {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>

60
src/layouts/tabbar.vue Normal file
View File

@ -0,0 +1,60 @@
<template>
<wd-config-provider :themeVars="themeVars">
<wd-notify />
<wd-toast />
<wd-message-box />
<!-- <privacy-popup></privacy-popup> -->
<slot></slot>
<wd-tabbar
fixed
:model-value="tabbarStore.getActive.name"
@change="handleChange"
bordered
safeAreaInsetBottom
placeholder
>
<wd-tabbar-item
v-for="(item, index) in tabbarStore.getTabbarItems"
:key="index"
:name="item.name"
:value="tabbarStore.getTabbarItemValue(item.name)"
:title="item.title"
:icon="item.icon"
></wd-tabbar-item>
</wd-tabbar>
</wd-config-provider>
</template>
<script lang="ts">
export default {
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: 'shared',
},
}
</script>
<script lang="ts" setup>
import { useTabbarStore } from '@/store/tabbar'
import { ConfigProviderThemeVars } from 'wot-design-uni'
const tabbarStore = useTabbarStore()
const themeVars = reactive<ConfigProviderThemeVars>({
colorTheme: '#fa4126',
tabsNavLineBgColor: 'red',
})
function handleChange({ value }) {
tabbarStore.setTabbarItemActive(value)
uni.navigateTo({
url: tabbarStore.getTabbarItemRoute(value),
})
}
onShow(() => {
// #ifdef APP-PLUS
uni.hideTabBar()
// #endif
})
</script>
<style lang="scss" scoped></style>

View File

@ -18,6 +18,7 @@
{
"path": "pages/index/index",
"type": "home",
"layout": "tabbar",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "首页"
@ -26,6 +27,7 @@
{
"path": "pages/about/about",
"type": "page",
"layout": "tabbar",
"style": {
"navigationBarTitleText": "关于",
"navigationStyle": "custom"

View File

@ -1,5 +1,6 @@
<route lang="json5">
{
layout: 'tabbar',
style: {
navigationBarTitleText: '关于',
navigationStyle: 'custom', //

View File

@ -1,6 +1,7 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page推荐使用json5更强大且允许注释 -->
<route lang="json5" type="home">
{
layout: 'tabbar',
style: {
navigationStyle: 'custom',
navigationBarTitleText: '首页',

View File

@ -4,13 +4,30 @@ export interface TabbarItem {
name: string
value: number | null
active: boolean
route: string
title: string
icon: string
}
export const useTabbarStore = defineStore('tabbar', {
state: (): { tabbarItems: TabbarItem[] } => ({
tabbarItems: [
{ name: 'index', value: null, active: true },
{ name: 'about', value: null, active: false },
{
name: 'index',
value: null,
active: true,
route: '/pages/index/index',
title: '首页',
icon: 'home',
},
{
name: 'about',
value: null,
active: false,
route: '/pages/about/about',
title: '关于',
icon: 'user',
},
],
}),
getters: {
@ -27,6 +44,12 @@ export const useTabbarStore = defineStore('tabbar', {
return item && item.value ? item.value : null
}
},
getTabbarItemRoute: (state) => {
return (name: string) => {
const item = state.tabbarItems.find((item) => item.name === name)
return (item && item.route) ?? null
}
},
},
actions: {
setTabbarItem(name: string, value: number) {

View File

@ -8,6 +8,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
FgNavbar: typeof import('./../components/fg-navbar/fg-navbar.vue')['default']
FgTabbar: typeof import('./../components/fg-tabbar/fg-tabbar.vue')['default']
Tabbar: typeof import('./../components/tabbar/tabbar.vue')['default']
}
}