fix(JlsBottomNav): 调整底栏加载失败或无数据时仅显示首页
新增getHomeOnlyTabbarItems工具方法用于获取仅包含首页的底栏项,替换所有兜底场景的默认项获取逻辑,更新README补充兜底规则说明,并补充缺失的组件类型声明
Showing
4 changed files
with
30 additions
and
7 deletions
| ... | @@ -13,6 +13,10 @@ declare module '@vue/runtime-core' { | ... | @@ -13,6 +13,10 @@ declare module '@vue/runtime-core' { |
| 13 | AudioBackground1: typeof import('./src/components/audioBackground1.vue')['default'] | 13 | AudioBackground1: typeof import('./src/components/audioBackground1.vue')['default'] |
| 14 | AudioList: typeof import('./src/components/audioList.vue')['default'] | 14 | AudioList: typeof import('./src/components/audioList.vue')['default'] |
| 15 | BottomNav: typeof import('./src/components/BottomNav.vue')['default'] | 15 | BottomNav: typeof import('./src/components/BottomNav.vue')['default'] |
| 16 | + ElButton: typeof import('element-plus/es')['ElButton'] | ||
| 17 | + ElInput: typeof import('element-plus/es')['ElInput'] | ||
| 18 | + ElOption: typeof import('element-plus/es')['ElOption'] | ||
| 19 | + ElSelect: typeof import('element-plus/es')['ElSelect'] | ||
| 16 | Floor: typeof import('./src/components/Floor/index.vue')['default'] | 20 | Floor: typeof import('./src/components/Floor/index.vue')['default'] |
| 17 | InfoPopup: typeof import('./src/components/InfoPopup.vue')['default'] | 21 | InfoPopup: typeof import('./src/components/InfoPopup.vue')['default'] |
| 18 | InfoPopupLite: typeof import('./src/components/InfoPopupLite.vue')['default'] | 22 | InfoPopupLite: typeof import('./src/components/InfoPopupLite.vue')['default'] |
| ... | @@ -27,14 +31,19 @@ declare module '@vue/runtime-core' { | ... | @@ -27,14 +31,19 @@ declare module '@vue/runtime-core' { |
| 27 | SvgIcon: typeof import('./src/components/Floor/svgIcon.vue')['default'] | 31 | SvgIcon: typeof import('./src/components/Floor/svgIcon.vue')['default'] |
| 28 | VanBackTop: typeof import('vant/es')['BackTop'] | 32 | VanBackTop: typeof import('vant/es')['BackTop'] |
| 29 | VanButton: typeof import('vant/es')['Button'] | 33 | VanButton: typeof import('vant/es')['Button'] |
| 34 | + VanCol: typeof import('vant/es')['Col'] | ||
| 30 | VanConfigProvider: typeof import('vant/es')['ConfigProvider'] | 35 | VanConfigProvider: typeof import('vant/es')['ConfigProvider'] |
| 31 | VanDialog: typeof import('vant/es')['Dialog'] | 36 | VanDialog: typeof import('vant/es')['Dialog'] |
| 37 | + VanField: typeof import('vant/es')['Field'] | ||
| 32 | VanFloatingPanel: typeof import('vant/es')['FloatingPanel'] | 38 | VanFloatingPanel: typeof import('vant/es')['FloatingPanel'] |
| 33 | VanIcon: typeof import('vant/es')['Icon'] | 39 | VanIcon: typeof import('vant/es')['Icon'] |
| 34 | VanImage: typeof import('vant/es')['Image'] | 40 | VanImage: typeof import('vant/es')['Image'] |
| 35 | VanImagePreview: typeof import('vant/es')['ImagePreview'] | 41 | VanImagePreview: typeof import('vant/es')['ImagePreview'] |
| 36 | VanLoading: typeof import('vant/es')['Loading'] | 42 | VanLoading: typeof import('vant/es')['Loading'] |
| 43 | + VanOverlay: typeof import('vant/es')['Overlay'] | ||
| 37 | VanPopup: typeof import('vant/es')['Popup'] | 44 | VanPopup: typeof import('vant/es')['Popup'] |
| 45 | + VanRow: typeof import('vant/es')['Row'] | ||
| 46 | + VanSlider: typeof import('vant/es')['Slider'] | ||
| 38 | VanSwipe: typeof import('vant/es')['Swipe'] | 47 | VanSwipe: typeof import('vant/es')['Swipe'] |
| 39 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] | 48 | VanSwipeItem: typeof import('vant/es')['SwipeItem'] |
| 40 | VanTab: typeof import('vant/es')['Tab'] | 49 | VanTab: typeof import('vant/es')['Tab'] | ... | ... |
| ... | @@ -9,7 +9,7 @@ | ... | @@ -9,7 +9,7 @@ |
| 9 | - [tabbar.api.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/tabbar.api.js) | 9 | - [tabbar.api.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/tabbar.api.js) |
| 10 | 底栏配置接口请求,当前使用 `/srv/?a=app_menu`。 | 10 | 底栏配置接口请求,当前使用 `/srv/?a=app_menu`。 |
| 11 | - [tabbar.utils.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/tabbar.utils.js) | 11 | - [tabbar.utils.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/tabbar.utils.js) |
| 12 | - 底栏数据归一化、默认项、顺序、icon class 解析、目标地址解析。 | 12 | + 底栏数据归一化、首页兜底、顺序、icon class 解析、目标地址解析。 |
| 13 | - [useTabbar.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/useTabbar.js) | 13 | - [useTabbar.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/useTabbar.js) |
| 14 | 组件内状态和加载逻辑,支持 `api` / `mock` 两种加载模式。 | 14 | 组件内状态和加载逻辑,支持 `api` / `mock` 两种加载模式。 |
| 15 | - [nav-state.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/nav-state.js) | 15 | - [nav-state.js](/Users/huyirui/program/itomix/git/map-demo/src/components/JlsBottomNav/nav-state.js) |
| ... | @@ -45,6 +45,15 @@ import JlsBottomNav from '@/components/JlsBottomNav'; | ... | @@ -45,6 +45,15 @@ import JlsBottomNav from '@/components/JlsBottomNav'; |
| 45 | 45 | ||
| 46 | `visible` 为 `true` 时组件才会渲染并尝试加载数据。 | 46 | `visible` 为 `true` 时组件才会渲染并尝试加载数据。 |
| 47 | 47 | ||
| 48 | +接口显示规则: | ||
| 49 | + | ||
| 50 | +- 只有接口成功并返回有效菜单时,才显示接口里的其他按钮 | ||
| 51 | +- 如果接口返回 `data: []` | ||
| 52 | +- 如果接口失败 | ||
| 53 | +- 如果接口结构异常 | ||
| 54 | + | ||
| 55 | +以上情况都统一只保留 `home` | ||
| 56 | + | ||
| 48 | ### 3. 激活态 | 57 | ### 3. 激活态 |
| 49 | 58 | ||
| 50 | 组件通过当前路由的 `activeTab` 识别高亮项,兼容以下写法: | 59 | 组件通过当前路由的 `activeTab` 识别高亮项,兼容以下写法: |
| ... | @@ -126,6 +135,9 @@ import { getJlsTabbarPreviewOptions } from '@/components/JlsBottomNav/preview'; | ... | @@ -126,6 +135,9 @@ import { getJlsTabbarPreviewOptions } from '@/components/JlsBottomNav/preview'; |
| 126 | ## 注意点 | 135 | ## 注意点 |
| 127 | 136 | ||
| 128 | - 组件默认按小程序 WebView 跳转方式调用 `wx.miniProgram.redirectTo / reLaunch`。 | 137 | - 组件默认按小程序 WebView 跳转方式调用 `wx.miniProgram.redirectTo / reLaunch`。 |
| 138 | +- 底栏显示兜底规则是“只保留首页”: | ||
| 139 | + - 只有接口成功并返回有效菜单时,才显示首页之外的其他项 | ||
| 140 | + - 接口空数组、失败、异常、无法归一化时,都只显示 `home` | ||
| 129 | - 当前跳转逻辑是: | 141 | - 当前跳转逻辑是: |
| 130 | - `home` 默认跳回小程序页 `/pages/index/index` | 142 | - `home` 默认跳回小程序页 `/pages/index/index` |
| 131 | - 其他项不会直接跳裸 H5 URL,而是优先使用接口返回的 `page_url` | 143 | - 其他项不会直接跳裸 H5 URL,而是优先使用接口返回的 `page_url` | ... | ... |
| ... | @@ -111,6 +111,8 @@ export const getDefaultTabbarItem = (key) => { | ... | @@ -111,6 +111,8 @@ export const getDefaultTabbarItem = (key) => { |
| 111 | export const getDefaultTabbarItems = () => | 111 | export const getDefaultTabbarItems = () => |
| 112 | TABBAR_ORDER.map((key) => getDefaultTabbarItem(key)).filter(Boolean); | 112 | TABBAR_ORDER.map((key) => getDefaultTabbarItem(key)).filter(Boolean); |
| 113 | 113 | ||
| 114 | +export const getHomeOnlyTabbarItems = () => [getDefaultTabbarItem('home')].filter(Boolean); | ||
| 115 | + | ||
| 114 | const buildTabbarPageUrl = (key, webviewUrl, webviewTitle, rawPageUrl = '') => { | 116 | const buildTabbarPageUrl = (key, webviewUrl, webviewTitle, rawPageUrl = '') => { |
| 115 | if (key === 'home') { | 117 | if (key === 'home') { |
| 116 | return rawPageUrl || '/pages/index/index'; | 118 | return rawPageUrl || '/pages/index/index'; |
| ... | @@ -224,12 +226,12 @@ const normalizeTabbarObjectItems = (rawMap = {}) => { | ... | @@ -224,12 +226,12 @@ const normalizeTabbarObjectItems = (rawMap = {}) => { |
| 224 | 226 | ||
| 225 | export const normalizeTabbarItems = (rawItems = []) => { | 227 | export const normalizeTabbarItems = (rawItems = []) => { |
| 226 | if (!Array.isArray(rawItems) || !rawItems.length) { | 228 | if (!Array.isArray(rawItems) || !rawItems.length) { |
| 227 | - return getDefaultTabbarItems(); | 229 | + return getHomeOnlyTabbarItems(); |
| 228 | } | 230 | } |
| 229 | 231 | ||
| 230 | const normalizedItems = rawItems.map((item) => normalizeTabbarItem(item)).filter(Boolean); | 232 | const normalizedItems = rawItems.map((item) => normalizeTabbarItem(item)).filter(Boolean); |
| 231 | 233 | ||
| 232 | - return normalizedItems.length ? normalizedItems : getDefaultTabbarItems(); | 234 | + return normalizedItems.length ? normalizedItems : getHomeOnlyTabbarItems(); |
| 233 | }; | 235 | }; |
| 234 | 236 | ||
| 235 | export const normalizeTabbarPayload = (rawPayload = null) => { | 237 | export const normalizeTabbarPayload = (rawPayload = null) => { |
| ... | @@ -245,7 +247,7 @@ export const normalizeTabbarPayload = (rawPayload = null) => { | ... | @@ -245,7 +247,7 @@ export const normalizeTabbarPayload = (rawPayload = null) => { |
| 245 | const objectPayload = rawPayload?.tab_items || rawPayload?.tabs || rawPayload?.menus || rawPayload; | 247 | const objectPayload = rawPayload?.tab_items || rawPayload?.tabs || rawPayload?.menus || rawPayload; |
| 246 | const normalizedItems = normalizeTabbarObjectItems(objectPayload); | 248 | const normalizedItems = normalizeTabbarObjectItems(objectPayload); |
| 247 | 249 | ||
| 248 | - return normalizedItems.length ? normalizedItems : getDefaultTabbarItems(); | 250 | + return normalizedItems.length ? normalizedItems : getHomeOnlyTabbarItems(); |
| 249 | }; | 251 | }; |
| 250 | 252 | ||
| 251 | export const resolveTabbarTargetUrl = (item = {}) => { | 253 | export const resolveTabbarTargetUrl = (item = {}) => { | ... | ... |
| ... | @@ -2,14 +2,14 @@ import { computed, reactive, readonly } from 'vue'; | ... | @@ -2,14 +2,14 @@ import { computed, reactive, readonly } from 'vue'; |
| 2 | import { getTabbarConfigAPI } from './tabbar.api'; | 2 | import { getTabbarConfigAPI } from './tabbar.api'; |
| 3 | import { | 3 | import { |
| 4 | getDefaultTabbarItem, | 4 | getDefaultTabbarItem, |
| 5 | - getDefaultTabbarItems, | 5 | + getHomeOnlyTabbarItems, |
| 6 | normalizeTabbarKey, | 6 | normalizeTabbarKey, |
| 7 | normalizeTabbarPayload, | 7 | normalizeTabbarPayload, |
| 8 | resolveTabbarTargetUrl, | 8 | resolveTabbarTargetUrl, |
| 9 | } from './tabbar.utils'; | 9 | } from './tabbar.utils'; |
| 10 | 10 | ||
| 11 | const state = reactive({ | 11 | const state = reactive({ |
| 12 | - tabItems: getDefaultTabbarItems(), | 12 | + tabItems: getHomeOnlyTabbarItems(), |
| 13 | loaded: false, | 13 | loaded: false, |
| 14 | loading: false, | 14 | loading: false, |
| 15 | loadMode: 'api', | 15 | loadMode: 'api', |
| ... | @@ -18,7 +18,7 @@ const state = reactive({ | ... | @@ -18,7 +18,7 @@ const state = reactive({ |
| 18 | let tabbarRequestPromise = null; | 18 | let tabbarRequestPromise = null; |
| 19 | 19 | ||
| 20 | const applyFallbackItems = () => { | 20 | const applyFallbackItems = () => { |
| 21 | - state.tabItems = getDefaultTabbarItems(); | 21 | + state.tabItems = getHomeOnlyTabbarItems(); |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | const resolveLoadMode = (options = {}) => (options.useMock ? 'mock' : 'api'); | 24 | const resolveLoadMode = (options = {}) => (options.useMock ? 'mock' : 'api'); | ... | ... |
-
Please register or login to post a comment