navigation.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * 全局导航工具函数
  3. * 统一管理页面跳转和返回逻辑
  4. */
  5. /**
  6. * 返回处理
  7. * 检查页面栈,如果是首页则跳转到主页,否则返回上一页
  8. * @param {Object} options 配置选项
  9. * @param {string} options.fallbackUrl 当无法返回时的跳转地址,默认为首页
  10. * @param {boolean} options.showLog 是否显示调试日志,默认为true
  11. */
  12. export const goBack = (options = {}) => {
  13. const {
  14. fallbackUrl = '/pages/main/index?tab=my',
  15. showLog = true
  16. } = options
  17. const pages = getCurrentPages()
  18. if (showLog) {
  19. console.log('当前页面栈长度:', pages.length)
  20. console.log('页面栈信息:', pages.map(page => page.route))
  21. }
  22. if (pages.length <= 1) {
  23. // 如果是首页,跳转到指定页面
  24. if (showLog) {
  25. console.log('当前是首页,跳转到:', fallbackUrl)
  26. }
  27. uni.reLaunch({
  28. url: fallbackUrl
  29. })
  30. } else {
  31. // 有上一页,正常返回
  32. if (showLog) {
  33. console.log('返回上一页')
  34. }
  35. uni.navigateBack()
  36. }
  37. }
  38. /**
  39. * 跳转处理
  40. * 根据目标页面类型选择合适的跳转方式
  41. * @param {string} url 目标页面路径
  42. * @param {Object} options 配置选项
  43. * @param {string} options.type 跳转类型:'navigate'|'redirect'|'reLaunch'|'switchTab'|'auto'
  44. * @param {boolean} options.showLog 是否显示调试日志,默认为true
  45. */
  46. export const goTo = (url, params = {}, options = {}) => {
  47. const {
  48. type = 'auto',
  49. showLog = true
  50. } = options
  51. // 构建完整的URL(包含参数)
  52. let fullUrl = url
  53. if (params && Object.keys(params).length > 0) {
  54. const queryString = Object.keys(params)
  55. .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
  56. .join('&')
  57. fullUrl = `${url}?${queryString}`
  58. }
  59. if (showLog) {
  60. console.log('智能跳转到:', fullUrl, '类型:', type, '参数:', params)
  61. }
  62. // 使用配置中的 tabbar 页面列表(当前为空,避免误判)
  63. const tabbarPages = navigationConfig?.tabbarPages || []
  64. // 自动判断跳转类型
  65. if (type === 'auto') {
  66. // 如果跳到主容器,使用 reLaunch 支持带参数刷新
  67. if (url.startsWith('/pages/main/index')) {
  68. uni.reLaunch({ url: fullUrl })
  69. } else if (tabbarPages.includes(url)) {
  70. // 理论上当前为空,不会进入
  71. uni.switchTab({ url })
  72. } else {
  73. uni.navigateTo({ url: fullUrl })
  74. }
  75. } else {
  76. // 使用指定的跳转类型
  77. switch (type) {
  78. case 'navigate':
  79. uni.navigateTo({ url: fullUrl })
  80. break
  81. case 'redirect':
  82. uni.redirectTo({ url: fullUrl })
  83. break
  84. case 'reLaunch':
  85. uni.reLaunch({ url: fullUrl })
  86. break
  87. case 'switchTab':
  88. uni.switchTab({ url }) // switchTab不支持参数
  89. break
  90. default:
  91. console.warn('未知的跳转类型:', type)
  92. uni.navigateTo({ url: fullUrl })
  93. }
  94. }
  95. }
  96. /**
  97. * 跳到主容器指定tab
  98. * @param {string} tabKey e.g. 'my' | 'todo' | 'statistics'
  99. */
  100. export const goToMainTab = (tabKey = 'my') => {
  101. const url = `/pages/main/index?tab=${encodeURIComponent(tabKey)}`
  102. uni.reLaunch({ url })
  103. }
  104. /**
  105. * 获取当前页面信息
  106. * @returns {Object} 当前页面信息
  107. */
  108. export const getCurrentPageInfo = () => {
  109. const pages = getCurrentPages()
  110. const currentPage = pages[pages.length - 1]
  111. return {
  112. route: currentPage?.route || '',
  113. options: currentPage?.options || {},
  114. stackLength: pages.length,
  115. isFirstPage: pages.length <= 1
  116. }
  117. }
  118. /**
  119. * 检查是否为tabbar页面
  120. * @param {string} url 页面路径
  121. * @returns {boolean} 是否为tabbar页面
  122. */
  123. export const isTabbarPage = (url) => {
  124. const tabbarPages = navigationConfig?.tabbarPages || []
  125. // 处理相对路径和绝对路径
  126. const normalizedUrl = url.startsWith('/') ? url : `/${url}`
  127. return tabbarPages.includes(normalizedUrl)
  128. }
  129. /**
  130. * 安全的页面跳转
  131. * 在跳转前检查页面栈,避免栈溢出
  132. * @param {string} url 目标页面路径
  133. * @param {Object} options 配置选项
  134. * @param {number} options.maxStackSize 最大页面栈大小,默认为10
  135. * @param {boolean} options.showLog 是否显示调试日志,默认为true
  136. */
  137. export const safeNavigate = (url, options = {}) => {
  138. const {
  139. maxStackSize = 10,
  140. showLog = true
  141. } = options
  142. const pages = getCurrentPages()
  143. if (showLog) {
  144. console.log('安全跳转检查,当前栈大小:', pages.length, '最大栈大小:', maxStackSize)
  145. }
  146. if (pages.length >= maxStackSize) {
  147. // 页面栈过深,使用redirectTo替换当前页面
  148. if (showLog) {
  149. console.log('页面栈过深,使用redirectTo替换当前页面')
  150. }
  151. uni.redirectTo({ url })
  152. } else {
  153. // 正常跳转
  154. goTo(url, { showLog })
  155. }
  156. }
  157. /**
  158. * 返回到指定页面
  159. * @param {string} targetRoute 目标页面路由
  160. * @param {Object} options 配置选项
  161. * @param {string} options.fallbackUrl 找不到目标页面时的跳转地址
  162. * @param {boolean} options.showLog 是否显示调试日志,默认为true
  163. */
  164. export const backToPage = (targetRoute, options = {}) => {
  165. const {
  166. fallbackUrl = '/pages/main/index?tab=my',
  167. showLog = true
  168. } = options
  169. const pages = getCurrentPages()
  170. // 查找目标页面在栈中的位置
  171. let targetIndex = -1
  172. for (let i = pages.length - 1; i >= 0; i--) {
  173. if (pages[i].route === targetRoute) {
  174. targetIndex = i
  175. break
  176. }
  177. }
  178. if (targetIndex >= 0) {
  179. // 找到目标页面,计算需要返回的层数
  180. const delta = pages.length - 1 - targetIndex
  181. if (showLog) {
  182. console.log('返回到页面:', targetRoute, '需要返回', delta, '层')
  183. }
  184. uni.navigateBack({ delta })
  185. } else {
  186. // 没找到目标页面,跳转到指定页面
  187. if (showLog) {
  188. console.log('未找到目标页面:', targetRoute, '跳转到:', fallbackUrl)
  189. }
  190. uni.reLaunch({ url: fallbackUrl })
  191. }
  192. }
  193. /**
  194. * 导航工具的默认配置
  195. */
  196. export const navigationConfig = {
  197. // 默认的fallback页面
  198. defaultFallbackUrl: '/pages/main/index?tab=my',
  199. // 是否显示调试日志
  200. showLog: true,
  201. // 最大页面栈大小
  202. maxStackSize: 10,
  203. // tabbar页面列表
  204. tabbarPages: [
  205. // 当前项目未使用原生tabBar,保留空数组避免误判
  206. ]
  207. }
  208. // 导出默认对象,方便统一导入
  209. export default {
  210. goBack,
  211. goTo,
  212. goToMainTab,
  213. getCurrentPageInfo,
  214. isTabbarPage,
  215. safeNavigate,
  216. backToPage,
  217. navigationConfig
  218. }