This commit is contained in:
owenchen committed 2026-10-13 17:02:14 +08:00
1 parent 32f237c4bf
commit 8a2adb0a92
18 files changed
+418 -53

No files matched your search

@@ -188,9 +188,8 @@ defineExpose({ refresh, clearSelection, selectedRows });
{{ filterCount }}
</text>
</view>
</view>
<view v-if="$slots.toolbar" class="toolbar-extra">
<slot name="toolbar" />
<!-- 页面可在此放次级动作按钮(如"新增"),排在筛选右侧、只留图标 -->
<slot name="toolbar-actions" />
</view>
</template>
@@ -302,17 +301,6 @@ defineExpose({ refresh, clearSelection, selectedRows });
border-radius: 16rpx;
}
/* 页面自定义的次级工具(如"新增")走白底一行,与搜索栏区分 */
.toolbar-extra {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
padding: 4rpx 24rpx 16rpx;
background-color: #ffffff;
border-bottom: 1rpx solid $u-border-color;
}
.card {
display: flex;
flex-direction: row;
@@ -2,8 +2,9 @@
</script>
<script setup lang="ts">
import { $u } from "uview-pro";
import { ref } from "vue";
import { $u, useLocale } from "uview-pro";
import { computed, onMounted } from "vue";
import { PAGE_PATHS, pageUrl, TAB_PAGES } from "@/router/routes";
import { useTabbarStore } from "@/stores";
defineOptions({
@@ -16,14 +17,82 @@ defineOptions({
},
});
const { tabbarList } = useTabbarStore();
const { t } = useLocale();
const store = useTabbarStore();
const current = ref<number>(0);
/**
* 把 store 里的"结构配置"翻译成 u-tabbar 需要的 item:文字按当前语言 t(langKey) 取,
* 因此切换语言时 tab 文案会自动跟着变(t 依赖 currentLocale,computed 会重新求值)。
*
* props 收进一个对象再 v-bind:既避开长标签被格式化器折行后触发 html-indent 对撞,
* 也集中覆盖 u-tabbar 几个默认值不合口味的 prop:
* - hideTabBar 必须 false:其 onMounted 默认调 uni.hideTabBar(),本项目是自定义 tabbar
* (无原生 pages.json tabBar),该调用必 reject 成 "hideTabBar:fail not TabBar page" 并被
* 全局错误边界弹成错误框。
* - midButton 必须 true:否则 item.midButton 的凸起样式不生效(中心「多媒体」大按钮)。
*/
const tabbarProps = computed(() => ({
modelValue: store.activeIndex,
list: store.tabs.map((tab, index) => ({
text: t(tab.langKey),
iconPath: tab.iconPath,
selectedIconPath: tab.selectedIconPath,
midButton: tab.midButton,
count: store.badges[index] ?? 0,
})),
activeColor: $u.color.primary,
midButton: true,
// 中心凸起的圆标图片尺寸:显式带单位,撑满 u-tabbar 写死的 100rpx 凸起圆(留一点白边当描边)
midButtonSize: "100rpx",
iconSize: 40,
textSize: 26,
hideTabBar: false,
}));
/**
* 由当前页面真实路径反推 tab 下标。
* 不依赖 activeIndex 的持久值:冷启动直达 / 403 回首页时持久值可能是上一次会话的旧下标,
* 按路由算才能保证高亮一定落在真正显示的这一页上。getCurrentPages 给的是不带前导斜杠的真实路径。
*/
function indexOfCurrentRoute(): number {
const pages = getCurrentPages();
const route = pages[pages.length - 1]?.route ?? "";
return TAB_PAGES.findIndex(name => PAGE_PATHS[name] === route);
}
onMounted(() => {
const index = indexOfCurrentRoute();
if (index >= 0) {
store.setActiveIndex(index);
}
});
/** item 未配 pagePath,u-tabbar 只会 emit change 而不自行 switchTab;跳转在这里做 */
function onChange(index: number): void {
if (index === store.activeIndex) {
return;
}
store.setActiveIndex(index);
// reLaunch 清空页面栈,符合"切 tab 不叠加历史"的直觉,也会被 nav-guard 正常拦截鉴权
uni.reLaunch({ url: pageUrl(TAB_PAGES[index]) });
}
</script>
<template>
<u-tabbar v-model="current" :list="tabbarList" :active-color="$u.color.primary" />
<u-tabbar v-bind="tabbarProps" @change="onChange" />
</template>
<style lang="scss" scoped>
/*
* 给底部导航加"上分隔线 + 向上投影",让它与页面内容之间有明显层次。
* 作用在 .u-tabbar__content(真正带背景色的那条)上:
* - border-top:比 u-border-top 自带的 1px 淡线更清晰一点;
* - box-shadow:负 y 偏移让阴影朝上投到页面上,形成浮起感。
* 注意:borderTop prop 仍保持默认 true —— 中心凸起按钮的缺口白圆(circle__border)
* 依赖它才渲染,关掉会让熊猫圆标和导航条衔接处出现割裂。
*/
:deep(.u-tabbar__content) {
border-top: 1rpx solid rgba(0, 0, 0, 0.06);
box-shadow: 0 -6rpx 28rpx rgba(0, 0, 0, 0.18);
}
</style>