uni-app 自定義路由封裝模塊詳解(附源碼逐行解讀)

🚀uni-app 自定義路由封裝模塊詳解(附源碼逐行解讀)

📌 請收藏 + 點贊 + 關注,獲取更多 uni-app 項目實用技巧!

在實際 uni-app 項目中,我們常常需要對 uni.navigateTouni.switchTab 等 API 做一層封裝,以便統一處理頁面跳轉、參數傳遞、登錄攔截等邏輯。本篇將完整展示一份功能強大的路由封裝方案,并逐行解釋其實現邏輯,幫助你構建更可控、易擴展的項目架構。


📦源碼展示(含說明性注釋)

👇以下是完整源碼,已集成:

  • 頁面路徑分析
  • query 和 params 分離
  • 登錄攔截(導航守衛)
  • 頁面跳轉封裝(支持多種跳轉模式)
  • 首頁識別與返回邏輯
  • 頁簽識別
  • 頁面棧方法調用
  • 登錄回調鉤子

📄 完整代碼如下(點擊右側小箭頭可展開逐行解讀):

點擊展開完整源碼逐行解讀
// 引入 lodash 的 last 方法,返回數組最后一個元素
import { last } from "lodash-es";// 引入 ctx 插件中編譯期注入的頁面配置、tabBar、subPackages 等
import { ctx } from "virtual:ctx";// 項目中封裝的 localStorage 工具
import { storage } from "../utils";// 引入全局 config 配置
import { config } from "../../config";type PushOptions = string | {path: string; // 路徑mode?: "navigateTo" | "redirectTo" | "reLaunch" | "switchTab" | "preloadPage"; // 跳轉方式events?: { [key: string]: (data: any) => void }; // 頁面間事件通信query?: { [key: string]: any }; // URL 參數params?: { [key: string]: any }; // 緩存參數isGuard?: boolean; // 是否啟用導航守衛[key: string]: any;
};type Tabs = {text?: string;pagePath: string;iconPath?: string;selectedIconPath?: string;[key: string]: any;
}[];// 獲取所有頁面配置
const routes = [...ctx.pages];// 處理子包中的頁面路徑
if (ctx.subPackages) {ctx.subPackages.forEach((a) => {a.pages.forEach((b) => {routes.push({...b,path: a.root + "/" + b.path,});});});
}// 注冊鉤子函數
const fn: { [key: string]: (...args: any[]) => any } = {};// 路由核心對象
const router = {// 讀取 tabBar 配置get tabs(): Tabs {if (ctx.tabBar) {return ctx.tabBar.list || [];} else {return [];}},// 全局樣式globalStyle: ctx.globalStyle,// 所有路由routes,// 當前頁面 URL query 參數get query() {const info = this.info();return { ...info?.query };},// 非 URL 參數,通過緩存傳遞get params() {return storage.get("router-params") || {};},// 頁面路徑配置get pages() {return {home: "/" + (ctx.tabBar ? this.tabs[0].pagePath : ctx.pages[0].path),...config.app.pages,};},// 當前頁面信息對象currentPage() {return last(getCurrentPages())!;},// 當前路徑get path() {return router.info()?.path;},// 當前頁面完整信息info() {const page = last(getCurrentPages());if (page) {const { route, $page, $vm, $getAppWebview }: any = page;const q: any = {};// 解析 query 參數try {$page?.fullPath.split("?")[1].split("&").forEach((e: string) => {const [k, v] = e.split("=");q[k] = decodeURIComponent(v);});} catch (e) {}const style = this.routes.find((e) => e.path == route)?.style;return {$vm,$getAppWebview,path: `/${route}`,fullPath: $page?.fullPath,query: q || {},isTab: this.isTab(route),style,isCustomNavbar: style?.navigationStyle == "custom",};}return null;},// 頁面跳轉主函數push(options: PushOptions) {if (typeof options === "string") {options = { path: options, mode: "navigateTo" };}let {path,mode = "navigateTo",animationType,animationDuration,events,success,fail,complete,query,params,isGuard = true,} = options;// 拼接 query 到 URLif (query) {let arr = [];for (let i in query) {if (query[i] !== undefined) arr.push(`${i}=${query[i]}`);}path += "?" + arr.join("&");}// 緩存傳參if (params) {storage.set("router-params", params);}const data = {url: path,animationType,animationDuration,events,success,fail,complete,};// 如果目標是 tab 頁,強制使用 switchTabif (this.isTab(path)) {mode = "switchTab";}const next = () => {switch (mode) {case "navigateTo":uni.navigateTo(data); break;case "redirectTo":uni.redirectTo(data); break;case "reLaunch":uni.reLaunch(data); break;case "switchTab":uni.switchTab(data); break;case "preloadPage":uni.preloadPage(data); break;}};// 啟用導航守衛if (fn.beforeEach && isGuard) {fn.beforeEach({ path: options.path, query }, next, (opt) => this.push(opt));} else {next();}},// 返回上一頁或首頁back(options?: UniApp.NavigateBackOptions) {if (this.isFirstPage()) {this.home();} else {uni.navigateBack(options || {});}},// 執行當前頁面某個方法callMethod(name: string, data?: any) {const { $vm } = this.info()!;if ($vm && $vm.$.exposed?.[name]) {return $vm.$.exposed[name](data);}},// 是否第一頁(判斷是否需要返回首頁)isFirstPage() {return getCurrentPages().length == 1;},// 是否是當前路徑isCurrentPage(path: string) {return this.info()?.path === path;},// 返回首頁home() {this.push(this.pages.home);},// 跳轉 Tab 頁switchTab(name: string) {const item = this.tabs.find((e) => e.pagePath.includes(name));if (item) {this.push({path: `/${item.pagePath}`,mode: "switchTab",});} else {console.error("Not found tab", name);}},// 是否是 Tab 頁isTab(path: string) {return !!this.tabs.find((e) => path === `/${e.pagePath}`);},// 跳轉登錄頁(支持 reLaunch)login(options?: { reLaunch: boolean }) {const { reLaunch = false } = options || {};this.push({path: this.pages.login,mode: reLaunch ? "reLaunch" : "navigateTo",isGuard: false,});},// 登錄成功后的回調處理nextLogin(type?: string) {const pages = getCurrentPages();const index = pages.findIndex((e) => this.pages.login.includes(e.route!));if (index <= 0) {this.home();} else {this.back({ delta: pages.length - index });}storage.set("loginType", type);if (fn.afterLogin) fn.afterLogin();uni.$emit("afterLogin", { type });},// 注冊路由鉤子函數(beforeEach)beforeEach(callback: (to: any, next: () => void, reject: (opt: PushOptions) => void) => void) {fn.beforeEach = callback;},// 登錄后執行回調afterLogin(callback: () => void) {fn.afterLogin = callback;},
};export { router };

?? 核心功能說明(重點功能歸納)

功能模塊描述說明
router.push()支持全模式頁面跳轉,封裝 query/params,支持守衛
router.info()獲取當前頁面詳細信息
router.callMethod()跨組件執行 exposed 方法
router.isTab()判斷路徑是否為 Tab 頁
router.beforeEach()注冊跳轉攔截器
router.nextLogin()登錄回調重定向功能
router.pages自動生成首頁路徑與配置路徑

?總結

該路由封裝模塊適用于 uni-app 項目中需要進行頁面跳轉邏輯統一管理的場景,具備:

  • 💡 統一跳轉 API:支持 navigateTo、switchTab、reLaunch 等
  • 🔒 導航守衛機制:登錄攔截與后置回調
  • 🔄 query/params 分離處理
  • 🧩 模塊化配置,支持掛載 ctx

你可以在此基礎上繼續拓展如:權限校驗、頁面緩存、歷史記錄管理、動畫過渡管理等功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/84541.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84541.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/84541.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

QML顯示圖片問題解決辦法

以前用qtwediget的時候&#xff0c;好像是放在qlabel或者什么組件上面&#xff0c;把圖片的路徑放上去就可以直接加載&#xff0c;但我用QML創建界面的時候就遇到了問題&#xff0c;哦對&#xff0c;qtwedget用qpixmap組件顯示圖片&#xff0c;也有image。話說回來&#xff0c;…

Vue中使用jsx

1. jsx的babel配置 1.1 在項目中使用jsx&#xff0c;需要添加對jsx的支持&#xff1a; jsx通常會通過Babel來進行轉換(React編寫的jsx就是通過babel轉換的)Vue中&#xff0c;只需要在Babel中配置對應的插件即可以下列舉需要支持轉換的案例&#xff1a; template -> vue-l…

Spring Cache+Redis緩存方案 vs 傳統redis緩存直接使用RedisTemplate 方案對比

結合 Spring Cache 和 Redis 的緩存方案&#xff08;即 Spring Cache Redis&#xff09;相較于普通的 Redis 緩存使用&#xff08;如直接通過 RedisTemplate 操作&#xff09;&#xff0c;具有以下顯著優勢&#xff1a; 具體實現方案請參考&#xff1a;Spring CacheRedis緩存…

Web應用安全漏洞掃描:原理、常用方法及潛在風險解析?

Web應用安全的關鍵環節在于進行漏洞掃描&#xff0c;這種掃描通過自動化或半自動化的方式&#xff0c;對應用進行安全測試。它能揭示出配置錯誤、代碼缺陷等眾多安全風險。接下來&#xff0c;我將詳細闡述這些情況。 掃描原理 它主要模擬攻擊者的行為&#xff0c;以探測和攻擊…

Spring中@Value注解:原理、加載順序與實戰指南

文章目錄 前言一、Value注解的核心原理1.1 容器啟動階段&#xff1a;環境準備1.2 Bean實例化階段&#xff1a;后置處理器介入1.3 值解析階段&#xff1a;雙引擎處理1. 占位符解析&#xff08;${...}&#xff09;2. SpEL表達式解析&#xff08;#{...}&#xff09; 1.4 類型轉換與…

MySQL 8配置文件詳解

MySQL 8 配置文件詳解 MySQL 8 的配置文件(my.cnf或my.ini)是MySQL服務器啟動時讀取的主要配置文件&#xff0c;它包含了服務器運行所需的各種參數設置。以下是MySQL 8配置文件的詳細解析&#xff1a; 配置文件位置 MySQL 8 會按照以下順序查找配置文件&#xff1a; /etc/m…

臺灣住宅IP哪家好,怎么找到靠譜的海外住宅IP代理商

探索臺灣住宅IP&#xff1a;如何找到靠譜的海外住宅IP代理商&#xff1f; 在當今數字化時代&#xff0c;海外住宅IP的需求日益增長&#xff0c;尤其在跨境電商、網絡營銷、數據抓取等領域。對于需要臺灣住宅IP的用戶來說&#xff0c;找到一家靠譜的海外住宅IP代理商至關重要。本…

讀研一些畢業感想

回首過往三年&#xff0c;從躊躇迷茫到明晰堅定&#xff0c;從稚嫩懵懂到明理成熟&#xff0c;一切只覺輕舟已過萬重山。 依稀記得我拉著行李箱跋山涉水來到學校的那天&#xff0c;早上從廣東中山乘坐10小時高鐵到北京西&#xff0c;然后坐1一個多小時地鐵到學校&#x…

《飛算JavaAI:穩定、高效、跨平臺的AI編程工具優勢解析》

隨著人工智能技術的不斷發展&#xff0c;AI編程工具越來越成為開發者們在研究和應用AI模型時不可或缺的利器。國內外的AI編程工具多種多樣&#xff0c;涵蓋了從基礎編程語言、框架到圖形化界面的多種選擇。然而&#xff0c;在這些工具中&#xff0c;飛算JavaAI作為一種基于Java…

day27/60重寫(補充)

DAY 27 函數專題2&#xff1a;裝飾器 ps&#xff1a;第一期day27對應5月16日 知識點回顧&#xff1a; 裝飾器的思想&#xff1a;進一步復用函數的裝飾器寫法注意內部函數的返回值 作業&#xff1a; 編寫一個裝飾器 logger&#xff0c;在函數執行前后打印日志信息&#xff08;如…

網傳西門子12億美元收購云原生工業軟件,云化PLM系統轉機在協同

近日&#xff0c;網傳西門子將以12億美元全現金交易收購云原生MES公司FlexFact&#xff0c;并整合其技術至Xcelerator工業軟件平臺。如果此次收購動作完成&#xff0c;將會成為西門子加速工業云轉型的標志性動作&#xff0c;背后的意義也極為深遠&#xff0c;不僅會直接響應競爭…

大模型筆記_檢索增強生成(RAG)

1. RAG的概念 RAG&#xff08;Retrieval-Augmented Generation&#xff09; 是一種結合 信息檢索&#xff08;Retrieval&#xff09;與文本生成&#xff08;Generation&#xff09;的模型架構&#xff0c;旨在通過動態引入外部知識庫或實時數據&#xff0c;提升大語言模型&…

Spring Security是如何完成身份認證的?

1. 用戶名和密碼被過濾器獲取到&#xff0c;封裝成 Authentication ,通常情況下是 UsernamePasswordAuthenticationToken 這個實現類。 2. AuthenticationManager 身份管理器負責驗證這個 Authentication 3. 認證成功后&#xff0c; AuthenticationManager 身份管理器返回一…

Python爬蟲實戰:研究xmltodict庫相關技術

1. 引言 1.1 研究背景與意義 氣象數據是環境研究、農業生產、城市規劃等領域的重要基礎。隨著互聯網技術的發展,越來越多的氣象數據以 XML 格式在網絡上公開。XML(可擴展標記語言)因其結構化和自描述性的特點,成為數據交換的標準格式之一。然而,這些數據通常分散在不同的…

中小企業無線局域網絡搭建與優化指南

1. 引言&#xff1a;無線網絡——驅動中國中小企業數字化轉型的引擎 無線網絡已成為現代企業運營的基礎設施&#xff0c;直接影響員工工作效率和客戶體驗。隨著Wi-Fi7技術的成熟和普及&#xff0c;中小企業網絡建設正迎來全新機遇。在數字經濟浪潮席卷全球的今天&#xff0c;無…

【已解決】python的kafka-python包連接kafka報認證失敗

先說原因&#xff1a;安裝python包的時候&#xff0c;多裝了一個kafka的包&#xff1a;kafka 1.3.5 我把py文件打包成二進制文件&#xff0c;在linux上執行就一直報認證失敗&#xff0c;后來確認登錄信息、認證方式沒有問題&#xff0c;把這個kafka包卸載…

傳輸層協議TCP(下)

上一篇https://blog.csdn.net/Small_entreprene/article/details/148193741?sharetypeblogdetail&sharerId148193741&sharereferPC&sharesourceSmall_entreprene&sharefrommp_from_link 接下來&#xff0c;我們來談論TCP具體的機制&#xff01; 具體TCP機制 …

洛谷B3612 【深進1.例1】求區間和

題目描述 給定 n 個正整數組成的數列 a1?,a2?,?,an? 和 m 個區間 [li?,ri?]&#xff0c;分別求這 m 個區間的區間和。 輸入格式 第一行&#xff0c;為一個正整數 n 。 第二行&#xff0c;為 n 個正整數 a1?,a2?,?,an? 第三行&#xff0c;為一個正整數 m 。 接下…

debian12 修改MariaDB數據庫存儲位置報錯

debian12 修改MariaDB數據庫存儲位置到home報錯 MariaDB 修改存儲路徑后啟動失敗問題解決 更改數據存儲位置 如果需要將數據存儲到其他位置&#xff08;如更大的分區&#xff09;&#xff1a; 停止 MariaDB 服務&#xff1a; bash sudo systemctl stop mariadb 創建新目錄并設…

【評測】flux-dev文生圖模型初體驗

回到目錄 【評測】flux-dev文生圖模型初體驗 1. 安裝基礎環境 參考 modelscope的Flux.1-dev頁面 2. 使用tongyi寫提示詞 幫我用英文寫3個&#xff0c;文生圖片1024*1024的提示詞&#xff0c;準備用flux.dev生成用 [pic03] 3. 運行代碼 4090D滿載運行&#xff0c; 1min左…