快速上手uni-simple-router
uni-simple-router
- 專為uniapp打造的路由器,和uniapp深度集成
- 通配小程序、App和H5端
- H5能完全使用vue-router開發(fā)
- 模塊化、查詢、通配符、路由參數(shù)
- 使 uni-app實(shí)現(xiàn)嵌套路由(僅H5端完全使用vue-router)
- uniapp用到了很多vue的api,但在路由管理的功能相對(duì)于vue-router還是比較欠缺的,比如全局導(dǎo)航守衛(wèi)
官方文檔:https://hhyang.cn/v2/start/quickstart.html
一、快速上手
// 針對(duì)uniapp HBuilder創(chuàng)建的項(xiàng)目,非cli構(gòu)建
// 1? NPM 安裝
npm install uni-simple-router
// 2? 初始化
npm install uni-read-pages // 配合vue.config.js自動(dòng)讀取pages.json作為路由表的方式,源碼例如下:擴(kuò)二
// 配置vue.config.js
const TransformPages = require('uni-read-pages')
const tfPages = new TransformPages()
module.exports = {
configureWebpack: {
plugins: [
new tfPages.webpack.DefinePlugin({
// 1? 配置全局變量
// ROUTES: JSON.stringify(tfPages.routes)
// 2? includes 可自定義,解析pages.json路由配字段的配置, 默認(rèn) ['path', 'name', 'aliasPath']
ROUTES: tfPages.webpack.DefinePlugin.runtimeValue(()=>{
const tf = new TransformPages({
includes: ['path', 'name', 'aliasPath']
})
return JSON.stringify(tfPages.routes)
},true)
})
]
}
}
// /Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli/node_modules/webpack 我的webpack包路徑,在軟件contents包文件里軟件自帶的webpack擴(kuò)一:webpack插件之DefinePlugin
- 允許創(chuàng)建一個(gè) 在編譯時(shí)可以配置的全局變量
- 場(chǎng)景:區(qū)分不同開發(fā)模式處理
// 1? 用法:每個(gè)傳進(jìn)DefinePlugin的鍵值都是一個(gè)標(biāo)志或者多個(gè)用.連接起來的標(biāo)識(shí)符
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
BROWSER_SUPPRTS_HTML5: true,
VERSION: JSON.stringify('abcde'),
TWO: '1+1',
'typeof window': JSON.stringify('object')
})
// 使用方式
console.log('Running App version', VERSION)
if(!BROWSER_SUPPRTS_HTML5) require("html5shiv")
// 2? 功能標(biāo)記 來作為一個(gè)flag標(biāo)識(shí)啟用和禁用構(gòu)建中的功能
new webpack.DefinePlugin({
'SHOW_PRESSION': JOSN.string(true)
})
// 3? 服務(wù):可以配置不同環(huán)境下的url
new webpack.DefinePlugin({
'DEV_URL': JSON.stringify(url_dev),
'PRO_URL': JSON.stringify(url_pro)
})擴(kuò)二:uni-read-pages 如何獲取pages.json中的路由
// 依賴的源碼 - 通過node的path模塊獲取pages.json文件中的任何信息 (部分是個(gè)人注釋)
const path = require('path')
const CONFIG = { includes: ['path', 'aliasPath', 'name'] } // 默認(rèn)獲取路由參數(shù)屬性
// process.cwd() 返回Node.js進(jìn)程的當(dāng)前工作目錄
// path.resolve(url1, 'abc') => url1/abc
const rootPath = path.resolve(process.cwd(), 'node_modules'); // 獲取根路徑
/** 解析絕對(duì)路徑
* @param {Object} dir
*/
function resolvePath(dir) {
return path.resolve(rootPath, dir);
}
// 類
class TransformPages {
constructor(config) {
// 組合 自定義獲取配置屬性
config = { ...CONFIG, ...config };
this.CONFIG = config;
// ↓本機(jī)文件路徑(HBuilderX包文件里自帶的webpack模塊路徑) /Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli/node_modules/webpack
this.webpack = require(resolvePath('webpack'));
this.uniPagesJSON = require(resolvePath('@dcloudio/uni-cli-shared/lib/pages.js'));
// TODO: 根據(jù)CONFIG解析pages.json中的路由信息 和 小程序 分包下的路由
this.routes = this.getPagesRoutes().concat(this.getNotMpRoutes());
}
// 獲取所有pages.json下的內(nèi)容 返回json
get pagesJson() {
return this.uniPagesJSON.getPagesJson();
}
// 通過讀取pages.json文件 生成直接可用的routes
getPagesRoutes(pages = this.pagesJson.pages, rootPath = null) {
const routes = [];
for (let i = 0; i < pages.length; i++) {
const item = pages[i];
const route = {};
for (let j = 0; j < this.CONFIG.includes.length; j++) {
const key = this.CONFIG.includes[j];
let value = item[key];
if (key === 'path') {
value = rootPath ? `/${rootPath}/${value}` : `/${value}`
}
if (key === 'aliasPath' && i == 0 && rootPath == null) {
route[key] = route[key] || '/'
} else if (value !== undefined) {
route[key] = value;
}
}
routes.push(route);
}
return routes;
}
// 解析小程序分包路徑
getNotMpRoutes() {
const { subPackages } = this.pagesJson;
let routes = [];
if (subPackages == null || subPackages.length == 0) {
return [];
}
for (let i = 0; i < subPackages.length; i++) {
const subPages = subPackages[i].pages;
const root = subPackages[i].root;
const subRoutes = this.getPagesRoutes(subPages, root);
routes = routes.concat(subRoutes)
}
return routes
}
/**
* 單條page對(duì)象解析
* @param {Object} pageCallback
* @param {Object} subPageCallback
*/
parsePages(pageCallback, subPageCallback) {
this.uniPagesJSON.parsePages(this.pagesJson, pageCallback, subPageCallback)
}
}
module.exports = TransformPages
二、H5模式
2.1 路由配置
import {RouterMount,createRouter} from 'uni-simple-router';
const router = createRouter({
// 路由配置
routes: [
{
path: '/pages/index/index', // 必須和pages.json中相同
extra: {
pageStyle: { color: '#f00' }// 及其它自定義參數(shù)
}
}
]
})
// 組件中可以通過 this.$Route 查看路由元信息2.2 完全使用vue-router開發(fā) (H5端)
- 嵌套路由時(shí),若使用name方式跳轉(zhuǎn),僅支持 this.$router.push({ name: children1 })
// 使用 vue-router開發(fā)將會(huì)失去uniapp的生命周期
const router = createRouter({
h5: {
vueRouterDev: true, // 完全使用vue-router開發(fā) 默認(rèn)是false
},
// 路由配置
routes: [
{
path: '/',
name: 'home',
component: () => import('@/common/router/home.vue'),
// 嵌套路由(僅H5端),小程序端會(huì)重新頁(yè)面打開
children: [
{
path: 'home/children1',
name: 'children1',
component: () => import('@/common/router/children1.vue')
},
{
path: 'home/children2',
name: 'children2',
component: () => import('@/common/router/children2.vue')
}
]
}
]
})2.3 H5 路由傳參
// 除vue-router外,美化url可以在基礎(chǔ)配置時(shí),定義aliasPath變量,設(shè)置路由別名(瀏覽器地址欄展示名稱)
// 別名的設(shè)置,如果設(shè)置了別名,通過push路徑的方式,必須使用aliasPath的路徑才能生效
const router = createRouter({
routes:[{
name:'router1',
//為了兼容其他端,此時(shí)的path不能少,必須和 pages.json中的頁(yè)面路徑匹配
path: "/pages/tabbar/tabbar-1/tabbar-1",
aliasPath: '/tabbar-1',
},]
});
// uni-simple-router路由跳轉(zhuǎn)
// aliasPath命名的路由 => name傳遞參數(shù)需 params
this.$Router.push({ name: 'detail', params: { id: 1 } })
// 帶查詢參數(shù),變成 /home/id=1 => path 對(duì)應(yīng)query,params失效
this.$Router.push({ path: '/pages/index/detail', query: { id: 1 }})2.4 H5端路由捕獲所有路由或404路由
path:'*' // 通常用于客戶端404錯(cuò)誤,如果是history模式,需要正確配置服務(wù)器 path: '/detail-*' // 路由的優(yōu)先級(jí)根據(jù) 定義的先后
2.5 路由懶加載
打包構(gòu)建應(yīng)用時(shí),Javascript包會(huì)變得非常大,影響頁(yè)面加載,把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問的時(shí)候才加載對(duì)應(yīng)組件。
const Foo = () => import('./Foo.vue')
// 把組件按組分塊 使用 命名 chunk
const Foo = () => import(/*webpackChunkName:"group-foo"*/ './Foo.vue')
const Bar = () => import(/*webpackChunkName:"group-foo"*/ './Bar.vue')三、小程序模式
注:小程序系列無法攔截原生tabbar及原生導(dǎo)航返回,如需攔截使用自定義tabbar、header
通過api進(jìn)行切換時(shí),像uni.switchTab()和this.$Router.pushTab()方法會(huì)觸發(fā)攔截的;僅底部原生tabbar進(jìn)行切換時(shí)不觸發(fā)攔截
強(qiáng)制觸發(fā)守衛(wèi):forceGuardEach(replaceAll, false) 每次調(diào)用api都會(huì)重新按流程觸發(fā)已經(jīng)聲明的所有守衛(wèi)
- 小程序端默認(rèn):插件api跳轉(zhuǎn)、uni導(dǎo)航api跳轉(zhuǎn)和首屏加載
- 使用路由守衛(wèi):通過點(diǎn)擊事件強(qiáng)制觸發(fā)、混入到onshow回調(diào)觸發(fā)
跳轉(zhuǎn)路由鎖:animationDuration保留給redirection\push足夠時(shí)間,等切換完成頁(yè)面后才放行下次跳轉(zhuǎn)
const router = createRouter({
platform: process.env.VUE_APP_PLATFORM,
// ① 路由鎖
applet: {
animationDuration: 300 // 默認(rèn)300ms
// animationDuration: 0 // 不精準(zhǔn) 只捕捉跳轉(zhuǎn)api下的complete函數(shù)
},
// ②優(yōu)雅解鎖 error.type: 0 表示 next(false)、1表示next(unknownType)、2表示加鎖狀態(tài),禁止跳轉(zhuǎn)、3表示在獲取頁(yè)面棧時(shí),頁(yè)面棧不夠level獲取
routerErrorEach:(error, router) => {
if (error.type === 3) {
router.$lockStatus = false
}
},
routes: [...ROUTES]
})四、路由跳轉(zhuǎn)
4.1 組件跳轉(zhuǎn)
vue-router中可以通過router-link組件進(jìn)行頁(yè)面跳轉(zhuǎn),uni-simple-router也提供了類似的組件,需要手動(dòng)注冊(cè)
// main.js
import Link from './node_modules/uni-simple-router/dist/link.vue'
Vue.component('Link', Link)// 通過path直接跳轉(zhuǎn) 并指定跳轉(zhuǎn)類型 <Link to="/tabbar1" navType="pushTab"> <button type="primary">使用path對(duì)象跳轉(zhuǎn)</button> </Link>
4.2 編程式導(dǎo)航
- 通過this.$Router獲取路由對(duì)象;push、pushTab、replace、back等api進(jìn)行路由跳轉(zhuǎn)
- 注:path搭配query參數(shù)、name搭配params參數(shù)
- 導(dǎo)航使用方式同vue-router
五、跨平臺(tái)模式
5.1 提前享用生命周期
uniapp由于只用onLoad接受options參數(shù)、onShow不接受;傳遞深度對(duì)象參數(shù)時(shí),需要先編碼再傳遞解碼
// 動(dòng)態(tài)改變參數(shù) 使 onLoad和onShow支持options
const router = createRouter({
platform: process.env.VUE_APP_PLATFORM,
routes: [...ROUTES],
beforeProxyHooks: {
onLoad(options, next){
next([router.currentRoute.query]);
},
onShow([options], next){
console.log(this);
const args=options||router.currentRoute.query;
next([args]);
},
},
});5.2 導(dǎo)航守衛(wèi)
全局前置守衛(wèi)
/**
* to: Route 即將進(jìn)入的目標(biāo)
* from: Route 當(dāng)前導(dǎo)航正要離開的路由
* next: Function 該方法的resolve鉤子函數(shù)必須調(diào)用,執(zhí)行效果依賴next方法的調(diào)用參數(shù)
* -- next()調(diào)用參數(shù):管道中的下個(gè)鉤子; next(false)中斷當(dāng)前導(dǎo)航;
* -- next('/')/({path: '/'})跳轉(zhuǎn)到一個(gè)不同的地址。當(dāng)前的導(dǎo)航被中斷,然后進(jìn)行一個(gè)新的導(dǎo)航
* -- next({delta: 2, NAVTYPE: 'back'}) 中斷當(dāng)前導(dǎo)航,調(diào)用新的跳轉(zhuǎn)類型,同時(shí)返回兩層頁(yè)面
**/
router.beforeEach((to, from, next) => {
// ...
// 1? next()
// 2? NAVTYPE定義跳轉(zhuǎn)方式,兩者相同非必填
if (to.name == 'tabbar-5') {
next({
name: 'router4',
params: {
msg: '我攔截了tab5并重定向到了路由4頁(yè)面上',
},
NAVTYPE: 'push'
});
} else{
next();
}
})全局后置守衛(wèi)
// 不接受next函數(shù)也不改變導(dǎo)航本身
router.afterEach((to,from) => {})路由獨(dú)享守衛(wèi)
// 路由配置上直接定義beforeEnter守衛(wèi)
const router = createRouter({
routes: [{
path: '/pages/home/index',
beforeEnter:(to,from,next) => {
// 參數(shù)同上全局前置守衛(wèi)
next()
}
}]
})組件內(nèi)的守衛(wèi)
// 組件內(nèi)配置beforeRouteLeave守衛(wèi) - 直接調(diào)用beforeRouteLeave方法
export default {
beforeRouteLeave(to, from, next) {
// 導(dǎo)航離開該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問組件實(shí)例this
next()
}
}六、路由守衛(wèi)-模塊化
// 1? 創(chuàng)建 router文件夾,模塊化配置 文件結(jié)構(gòu) |+------------------------+| | router | | |+--------------------+| | | | modules | | | | |+----------------+| | | | | | home.js | | | | | | index.js | | | | | |+----------------+| | | | |+--------------------+| | | index.js | |+------------------------+|
// home.js
const home = [
{
path: '/pages/home/index',
name: 'home'
}
]
export default home// modules下的index.js是一個(gè)模塊讀取
// ① require.context(directory, useSubdirectories, regExp) 具體詳情:如下擴(kuò)三
const files = require.context('.',false,/.js$/)
const modules = []
files.keys().forEach(key => {
if (key === './index.js') return
const item = files(key).default
modules.push(...item)
})
export default modules // 將所有模塊的路由模塊整合到一起, routes Array// router下的index.js 路由守衛(wèi)
import modules from './modules/index.js'
import Vue from 'vue'
import CreateRouter from 'uni-simple-router'
import store from '@/store/store.js'
Vue.use(CreateRouter)
//初始化
const router = new CreateRouter({
APP: {
holdTabbar: false //默認(rèn)true
},
h5: {
vueRouterDev: true, //完全使用vue-router開發(fā) 默認(rèn) false
},
// 也可以 通過uni-read-pages來讀取pages.json文件的路由表,配合vue.config.js
// router: [...ROUTES] // ROUTES是通過webpack的defaultPlugin編譯成全局變量,具體操作上文
routes: [...modules] //路由表
});
//全局路由前置守衛(wèi)
router.beforeEach((to, from, next) => {
// 首先判斷是否存在路由信息
//不存在就先調(diào)用接口得到數(shù)據(jù)
})
// 全局路由后置守衛(wèi)
router.afterEach((to, from) => {})
export default router;
擴(kuò)三、require.context用法
// require.context(directory, useSubdirectories, regExp) // directory: 表示檢索的目錄 // useSubdirectories: 表示是否檢索子文件夾 // regExp: 匹配文件的正則表達(dá)式 // 返回值: resolve是一個(gè)函數(shù),返回已解析請(qǐng)求的模塊ID; keys是一個(gè)函數(shù),它返回上下文模塊可以處理的所有可能請(qǐng)求的數(shù)組; // 使用場(chǎng)景:①用來組件內(nèi)引入多個(gè)組件;②在main.js內(nèi)引入大量公共組件;
// ①組件內(nèi)引入多個(gè)組件 - webpack
const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/) //值類型 ['./home.js', 'detail.js',...]
const modules = {}
files.keys().forEach(key => {
const name = paths.basename(key, '.vue') // 去掉文件名的 .vue后綴
modules[name] = files(key).default || files(key)
})
// modules { home: '{module樣式路徑}', detail: '{}', ... }
export default {
...,
data() { return {}},
components: modules
}// ②在main.js內(nèi)引入大量公共組件
import Vue from 'vue'
// 引入自定義組件
const requireComponents = require.context('../views/components',true,'/\.vue/')
// 遍歷出每個(gè)數(shù)組的路徑
requireComponents.keys().forEach(fileName => {
const reqCom = requireComponents(fileName)
// 獲取組件名
const reqComName = reqCom.name || fileName.replace(/\.\/(.*)\.vue/, '$1')
// 組件掛載
Vue.components(reqComName, reqCom.default || reqCom)
})到此這篇關(guān)于uni-simple-router的文章就介紹到這了,更多相關(guān)uni-simple-router內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS笛卡爾積算法與多重?cái)?shù)組笛卡爾積實(shí)現(xiàn)方法示例
這篇文章主要介紹了JS笛卡爾積算法與多重?cái)?shù)組笛卡爾積實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了javascript根據(jù)對(duì)象或數(shù)組生成笛卡爾積的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
JS實(shí)現(xiàn)table表格內(nèi)針對(duì)某列內(nèi)容進(jìn)行即時(shí)搜索篩選功能
這篇文章主要介紹了JS實(shí)現(xiàn)table表格內(nèi)針對(duì)某列內(nèi)容進(jìn)行即時(shí)搜索篩選功能,涉及javascript針對(duì)HTML元素的遍歷、屬性動(dòng)態(tài)修改相關(guān)操作技巧,需要的朋友可以參考下2018-05-05
JS檢測(cè)window.open打開的窗口是否關(guān)閉
在開發(fā)中遇到需要在打開窗口的同時(shí)給父窗口添加遮罩防止用戶誤操作,而在窗口關(guān)閉時(shí)需要去掉父窗口的遮罩以便用戶操作。所以可以利用setInterval()來周期性的檢測(cè)打開的窗口是否關(guān)閉2017-06-06
JS回調(diào)函數(shù)原理與用法詳解【附PHP回調(diào)函數(shù)】
這篇文章主要介紹了JS回調(diào)函數(shù)原理與用法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript回調(diào)函數(shù)的概念、原理、用法,并給出了PHP回調(diào)函數(shù)的使用示例,需要的朋友可以參考下2019-07-07
Js實(shí)現(xiàn)兩個(gè)跨域頁(yè)面進(jìn)行跳轉(zhuǎn)傳參的方案詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript中實(shí)現(xiàn)兩個(gè)跨域頁(yè)面進(jìn)行跳轉(zhuǎn)傳參的方案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
認(rèn)識(shí)less和webstrom的less配置方法
下面小編就為大家?guī)硪黄J(rèn)識(shí)less和webstrom的less配置方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08
JavaScript實(shí)現(xiàn)伸縮二級(jí)菜單
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)伸縮二級(jí)菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
JS簡(jiǎn)單編號(hào)生成器實(shí)現(xiàn)方法(附demo源碼下載)
這篇文章主要介紹了JS簡(jiǎn)單編號(hào)生成器實(shí)現(xiàn)方法,涉及JavaScript針對(duì)表單與字符串操作的相關(guān)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-04-04
js+css 實(shí)現(xiàn)遮罩居中彈出層(隨瀏覽器窗口滾動(dòng)條滾動(dòng))
本文為大家詳細(xì)介紹下使用js實(shí)現(xiàn)遮罩彈出層居中,且隨瀏覽器窗口滾動(dòng)條滾動(dòng),示例代碼如下,感興趣的朋友可以參考下2013-12-12

