Files

204 lines
5.9 KiB
JavaScript
Raw Permalink Normal View History

2026-08-19 08:17:18 +08:00
/**
* 底栏路由对齐:高亮只认当前页 path
* 动画优先打到官方 custom-tab-bar 单例,页内 ThemeTabBar 只作占位/兜底
* 真机用本地 PNG:微信会丢掉内联 SVG mask,只剩色块
* 套餐项受 features.package_enabled 控制,pages.json 仍声明 4 个 tab
*/
import { getThemeFeatures } from '@/utils/theme'
export const ALL_TAB_PAGES = [
{ pagePath: 'pages/goods/index', text: '首页', key: 'home', icon: '/static/tabbar/v2/home.png', iconOn: '/static/tabbar/v2/home-fill.png' },
{ pagePath: 'pages/package/index', text: '套餐', key: 'package', icon: '/static/tabbar/v2/package.png', iconOn: '/static/tabbar/v2/package-fill.png' },
{ pagePath: 'pages/order/list', text: '订单', key: 'order', icon: '/static/tabbar/v2/order.png', iconOn: '/static/tabbar/v2/order-fill.png' },
{ pagePath: 'pages/mine/mine', text: '我', key: 'mine', icon: '/static/tabbar/v2/mine.png', iconOn: '/static/tabbar/v2/mine-fill.png' },
]
/** 兼容旧引用:默认全量;运行时请用 getTabPages() */
export const TAB_PAGES = ALL_TAB_PAGES
/** 按应用开关过滤自定义底栏,关套餐时回到 3 项 */
export function getTabPages() {
const enabled = getThemeFeatures().package_enabled
return ALL_TAB_PAGES.filter((item) => item.key !== 'package' || enabled)
}
let nativeBar = null
let pageBar = null
const barsByRoute = {}
let pendingIndex = -1
let lastSelected = 0
export function getLastSelected() {
return lastSelected
}
export function setLastSelected(index) {
if (index >= 0) lastSelected = index
}
export function normalizeRoute(route) {
return String(route || '').replace(/^\//, '').split('?')[0]
}
export function currentRoute() {
const pages = getCurrentPages()
const last = pages[pages.length - 1]
return last ? normalizeRoute(last.route) : ''
}
export function currentTabIndex() {
const path = currentRoute()
return getTabPages().findIndex((item) => item.pagePath === path)
}
export function registerNativeTabBar(vm) {
nativeBar = vm
}
export function unregisterNativeTabBar(vm) {
if (nativeBar === vm) nativeBar = null
}
export function peekNativeBar() {
return nativeBar
}
export function registerPageTabBar(vm) {
pageBar = vm
}
export function unregisterPageTabBar(vm) {
if (pageBar === vm) pageBar = null
Object.keys(barsByRoute).forEach((key) => {
if (barsByRoute[key] === vm) delete barsByRoute[key]
})
}
/** Vue3 官方栏经常包一层 $vm,统一拆到带 syncFromRoute 的实例 */
export function unwrapTabBar(bar) {
if (!bar) return null
if (typeof bar.syncFromRoute === 'function') return bar
if (bar.$vm && typeof bar.$vm.syncFromRoute === 'function') return bar.$vm
const refs = (bar.$refs) || (bar.$vm && bar.$vm.$refs) || {}
const child = refs.bar
if (child && typeof child.syncFromRoute === 'function') return child
if (child && child.$vm && typeof child.$vm.syncFromRoute === 'function') return child.$vm
return null
}
/** 优先官方单例,没有再拿当前页那一份 */
export function resolvePageTabBar(ctx) {
if (nativeBar && typeof nativeBar.syncFromRoute === 'function') return nativeBar
try {
if (ctx && typeof ctx.getTabBar === 'function') {
const official = unwrapTabBar(ctx.getTabBar())
if (official) {
nativeBar = official
return official
}
}
} catch (err) {
/* 官方栏未就绪 */
}
let bar = null
const refs = ctx && ctx.$refs ? ctx.$refs : {}
bar = refs.themeTabBar
if (Array.isArray(bar)) bar = bar[0]
bar = unwrapTabBar(bar)
if (!bar) {
try {
if (ctx && typeof ctx.selectComponent === 'function') {
bar = unwrapTabBar(ctx.selectComponent('#themeTabBar') || ctx.selectComponent('.theme-tab-bar'))
}
} catch (err) {
bar = null
}
}
const path = currentRoute()
if (!bar) bar = unwrapTabBar((path && barsByRoute[path]) || pageBar)
if (bar) {
pageBar = bar
if (path) barsByRoute[path] = bar
return bar
}
return null
}
export function setPendingTab(index) {
pendingIndex = index
}
export function peekPendingTab() {
return pendingIndex
}
export function consumePendingTab() {
const value = pendingIndex
pendingIndex = -1
return value
}
/**
* 点底栏:记下起点和目标。不要在 switchTab complete 里清掉,
* 微信 complete 经常在旧页还是栈顶时就触发,清掉就播不出滑动。
*/
export function markTabTap(fromIndex, toIndex) {
if (fromIndex >= 0) lastSelected = fromIndex
pendingIndex = toIndex
}
/** 目标页对上对齐才算这次点击,并吃掉,避免 onShow 再滑一次 */
export function takeTabTap(index) {
if (pendingIndex !== index) return false
pendingIndex = -1
return true
}
/** switchTab 失败:清掉点击,栏保持旧高亮 */
export function clearTabTap() {
pendingIndex = -1
}
/**
* 官方栏已是 custom:true,再调 hideTabBar 会抛
* hideTabBar:fail custom Tabbar,这里刻意空实现
*/
export function hideNativeTabBar() {}
/**
* 把底栏 selected 对齐到栈顶路由
* 先打官方单例,保证胶囊/圆点是同一颗在滑
*/
export function syncTabBarByRoute(ctx, extra) {
const selected = currentTabIndex()
if (selected < 0) return
const apply = (bar) => {
const vm = unwrapTabBar(bar)
if (!vm) return false
if (typeof vm.syncFromRoute === 'function') {
vm.syncFromRoute(selected, extra || {})
return true
}
if (typeof vm.setData === 'function') {
vm.setData({ selected })
return true
}
return false
}
if (apply(resolvePageTabBar(ctx))) return
try {
if (apply(ctx && typeof ctx.getTabBar === 'function' ? ctx.getTabBar() : null)) return
} catch (err) {
/* 官方栏未就绪 */
}
setTimeout(() => {
try {
apply(ctx && typeof ctx.getTabBar === 'function' ? ctx.getTabBar() : null)
apply(resolvePageTabBar(ctx))
} catch (err) {
/* 重试失败忽略 */
}
}, 80)
}