feat(tabbar): 实现新的底部导航栏布局和功能
- 将原有tabbar组件重构为layout布局方式 - 新增tabbar store管理导航项状态和路由 - 为首页和关于页添加tabbar布局配置 - 移除旧的tabbar组件实现 - 添加tabbar路由跳转功能 - 更新类型定义以支持新组件 ``` 这个提交消息: 1. 使用feat类型,因为这是新增功能 2. 添加了scope(tabbar)明确修改范围 3. 简明描述了主要变更内容 4. 使用中文符合要求 5. 保持了50字符以内的描述行 6. 在正文中列出了主要变更点而不重复描述
This commit is contained in:
parent
e123a5cb1b
commit
27f23173fd
@ -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 }) // 确保传入的是tabBar页面的URL
|
|
||||||
}
|
|
||||||
|
|
||||||
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
60
src/layouts/tabbar.vue
Normal 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>
|
@ -18,6 +18,7 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"type": "home",
|
"type": "home",
|
||||||
|
"layout": "tabbar",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "首页"
|
"navigationBarTitleText": "首页"
|
||||||
@ -26,6 +27,7 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/about/about",
|
"path": "pages/about/about",
|
||||||
"type": "page",
|
"type": "page",
|
||||||
|
"layout": "tabbar",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "关于",
|
"navigationBarTitleText": "关于",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<route lang="json5">
|
<route lang="json5">
|
||||||
{
|
{
|
||||||
|
layout: 'tabbar',
|
||||||
style: {
|
style: {
|
||||||
navigationBarTitleText: '关于',
|
navigationBarTitleText: '关于',
|
||||||
navigationStyle: 'custom', // 开启自定义导航栏
|
navigationStyle: 'custom', // 开启自定义导航栏
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
|
<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
|
||||||
<route lang="json5" type="home">
|
<route lang="json5" type="home">
|
||||||
{
|
{
|
||||||
|
layout: 'tabbar',
|
||||||
style: {
|
style: {
|
||||||
navigationStyle: 'custom',
|
navigationStyle: 'custom',
|
||||||
navigationBarTitleText: '首页',
|
navigationBarTitleText: '首页',
|
||||||
|
@ -4,13 +4,30 @@ export interface TabbarItem {
|
|||||||
name: string
|
name: string
|
||||||
value: number | null
|
value: number | null
|
||||||
active: boolean
|
active: boolean
|
||||||
|
route: string
|
||||||
|
title: string
|
||||||
|
icon: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTabbarStore = defineStore('tabbar', {
|
export const useTabbarStore = defineStore('tabbar', {
|
||||||
state: (): { tabbarItems: TabbarItem[] } => ({
|
state: (): { tabbarItems: TabbarItem[] } => ({
|
||||||
tabbarItems: [
|
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: {
|
getters: {
|
||||||
@ -27,6 +44,12 @@ export const useTabbarStore = defineStore('tabbar', {
|
|||||||
return item && item.value ? item.value : null
|
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: {
|
actions: {
|
||||||
setTabbarItem(name: string, value: number) {
|
setTabbarItem(name: string, value: number) {
|
||||||
|
1
src/types/components.d.ts
vendored
1
src/types/components.d.ts
vendored
@ -8,6 +8,7 @@ export {}
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
FgNavbar: typeof import('./../components/fg-navbar/fg-navbar.vue')['default']
|
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']
|
Tabbar: typeof import('./../components/tabbar/tabbar.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user