feat(导航): 实现小程序底部导航激活状态与跳转优化
添加 CHECKIN_ACTIVE_TAB 常量及 resolveCheckinActiveTab 函数,用于解析路由参数中的激活标签页 重构 JlsBottomNav 组件,使用新的解析函数并实现根据 activeTab 高亮对应导航项 将小程序内跳转从 navigateTo 改为 redirectTo 以避免页面栈累积 更新相关单元测试以覆盖新增功能
Showing
3 changed files
with
41 additions
and
10 deletions
| ... | @@ -6,7 +6,9 @@ describe('checkin nav mode helpers', function () { | ... | @@ -6,7 +6,9 @@ describe('checkin nav mode helpers', function () { |
| 6 | it('resolves nav mode and map height from route query', async function () { | 6 | it('resolves nav mode and map height from route query', async function () { |
| 7 | const { | 7 | const { |
| 8 | CHECKIN_NAV_MODE, | 8 | CHECKIN_NAV_MODE, |
| 9 | + CHECKIN_ACTIVE_TAB, | ||
| 9 | resolveCheckinNavMode, | 10 | resolveCheckinNavMode, |
| 11 | + resolveCheckinActiveTab, | ||
| 10 | getCheckinMapHeight, | 12 | getCheckinMapHeight, |
| 11 | } = await import('../src/views/checkin/nav-mode.js'); | 13 | } = await import('../src/views/checkin/nav-mode.js'); |
| 12 | 14 | ||
| ... | @@ -17,6 +19,13 @@ describe('checkin nav mode helpers', function () { | ... | @@ -17,6 +19,13 @@ describe('checkin nav mode helpers', function () { |
| 17 | CHECKIN_NAV_MODE.LEGACY, | 19 | CHECKIN_NAV_MODE.LEGACY, |
| 18 | ); | 20 | ); |
| 19 | 21 | ||
| 22 | + expect(resolveCheckinActiveTab({ activeTab: 'home' })).to.equal(CHECKIN_ACTIVE_TAB.HOME); | ||
| 23 | + expect(resolveCheckinActiveTab({ activeTab: 'message' })).to.equal( | ||
| 24 | + CHECKIN_ACTIVE_TAB.MESSAGE, | ||
| 25 | + ); | ||
| 26 | + expect(resolveCheckinActiveTab({ activeTab: 'mine' })).to.equal(CHECKIN_ACTIVE_TAB.MINE); | ||
| 27 | + expect(resolveCheckinActiveTab({ activeTab: 'unexpected' })).to.equal(''); | ||
| 28 | + | ||
| 20 | expect( | 29 | expect( |
| 21 | getCheckinMapHeight({ | 30 | getCheckinMapHeight({ |
| 22 | isMiniProgramWebView: false, | 31 | isMiniProgramWebView: false, | ... | ... |
| ... | @@ -23,6 +23,7 @@ import HomeIcon from '@nutui/icons-vue/dist/es/icons/Home.js'; | ... | @@ -23,6 +23,7 @@ import HomeIcon from '@nutui/icons-vue/dist/es/icons/Home.js'; |
| 23 | import MessageIcon from '@nutui/icons-vue/dist/es/icons/Message.js'; | 23 | import MessageIcon from '@nutui/icons-vue/dist/es/icons/Message.js'; |
| 24 | import MyIcon from '@nutui/icons-vue/dist/es/icons/My.js'; | 24 | import MyIcon from '@nutui/icons-vue/dist/es/icons/My.js'; |
| 25 | import wx from 'weixin-js-sdk'; | 25 | import wx from 'weixin-js-sdk'; |
| 26 | +import { resolveCheckinActiveTab } from '@/views/checkin/nav-mode.js'; | ||
| 26 | 27 | ||
| 27 | const ACTIVE_COLOR = '#a67939'; | 28 | const ACTIVE_COLOR = '#a67939'; |
| 28 | const INACTIVE_COLOR = '#8b95a7'; | 29 | const INACTIVE_COLOR = '#8b95a7'; |
| ... | @@ -39,16 +40,12 @@ const navItems = [ | ... | @@ -39,16 +40,12 @@ const navItems = [ |
| 39 | { name: 'mine', path: '/pages/mine/index', icon: MyIcon, label: '我的' }, | 40 | { name: 'mine', path: '/pages/mine/index', icon: MyIcon, label: '我的' }, |
| 40 | ]; | 41 | ]; |
| 41 | 42 | ||
| 42 | -const reservedActiveTab = computed(() => { | 43 | +const currentActiveTab = computed(() => { |
| 43 | - const rawTab = Array.isArray(route.query.activeTab) ? route.query.activeTab[0] : route.query.activeTab; | 44 | + return resolveCheckinActiveTab(route.query || {}); |
| 44 | - return String(rawTab || '').trim().toLowerCase(); | ||
| 45 | }); | 45 | }); |
| 46 | 46 | ||
| 47 | -const isActive = () => { | 47 | +const isActive = (name) => { |
| 48 | - // 地图页目前不属于 JLS tab 列表中的任何一项。 | 48 | + return currentActiveTab.value === name; |
| 49 | - // activeTab 参数先预留,待业务确认后再决定是否映射到某个 tab 并启用高亮。 | ||
| 50 | - void reservedActiveTab.value; | ||
| 51 | - return false; | ||
| 52 | }; | 49 | }; |
| 53 | 50 | ||
| 54 | const getIconColor = (name) => { | 51 | const getIconColor = (name) => { |
| ... | @@ -60,8 +57,8 @@ const navigate = (path) => { | ... | @@ -60,8 +57,8 @@ const navigate = (path) => { |
| 60 | return; | 57 | return; |
| 61 | } | 58 | } |
| 62 | 59 | ||
| 63 | - if (wx?.miniProgram?.navigateTo) { | 60 | + if (wx?.miniProgram?.redirectTo) { |
| 64 | - wx.miniProgram.navigateTo({ | 61 | + wx.miniProgram.redirectTo({ |
| 65 | url: path, | 62 | url: path, |
| 66 | fail: () => { | 63 | fail: () => { |
| 67 | wx?.miniProgram?.reLaunch?.({ url: path }); | 64 | wx?.miniProgram?.reLaunch?.({ url: path }); | ... | ... |
| ... | @@ -4,6 +4,12 @@ export const CHECKIN_NAV_MODE = { | ... | @@ -4,6 +4,12 @@ export const CHECKIN_NAV_MODE = { |
| 4 | NONE: 'none', | 4 | NONE: 'none', |
| 5 | }; | 5 | }; |
| 6 | 6 | ||
| 7 | +export const CHECKIN_ACTIVE_TAB = { | ||
| 8 | + HOME: 'home', | ||
| 9 | + MESSAGE: 'message', | ||
| 10 | + MINE: 'mine', | ||
| 11 | +}; | ||
| 12 | + | ||
| 7 | const NAV_HEIGHT = '80px'; | 13 | const NAV_HEIGHT = '80px'; |
| 8 | 14 | ||
| 9 | export function resolveCheckinNavMode(query = {}) { | 15 | export function resolveCheckinNavMode(query = {}) { |
| ... | @@ -32,3 +38,22 @@ export function getCheckinMapHeight({ | ... | @@ -32,3 +38,22 @@ export function getCheckinMapHeight({ |
| 32 | 38 | ||
| 33 | return `calc(100vh - ${navHeight})`; | 39 | return `calc(100vh - ${navHeight})`; |
| 34 | } | 40 | } |
| 41 | + | ||
| 42 | +export function resolveCheckinActiveTab(query = {}) { | ||
| 43 | + const rawTab = Array.isArray(query.activeTab) ? query.activeTab[0] : query.activeTab; | ||
| 44 | + const normalizedTab = String(rawTab || '').trim().toLowerCase(); | ||
| 45 | + | ||
| 46 | + if (normalizedTab === CHECKIN_ACTIVE_TAB.HOME) { | ||
| 47 | + return CHECKIN_ACTIVE_TAB.HOME; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + if (normalizedTab === CHECKIN_ACTIVE_TAB.MESSAGE) { | ||
| 51 | + return CHECKIN_ACTIVE_TAB.MESSAGE; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + if (normalizedTab === CHECKIN_ACTIVE_TAB.MINE) { | ||
| 55 | + return CHECKIN_ACTIVE_TAB.MINE; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + return ''; | ||
| 59 | +} | ... | ... |
-
Please register or login to post a comment