笔记中的内容仅适用于HBulider构建的uniapp项目,通过其他方式构建的uniapp项目请参考uni-simple-router官网 uni-simple-router (hhyang.cn)
uniapp用到了vue的很多api,但在路由管理的功能上相较于vue-router还是比较欠缺的,比如全局导航守卫。
我们可以通uniapp的插件uni-simple-router来实现类似于vue-router的功能,但多端兼容时,一些用法还需要注意,我们会讲到。
如果你的项目没有使用package,请先初始化:
$ npm init -y
安装依赖:
$ npm install uni-simple-router uni-read-pages
uni-read-pages的作用是:读取uniapp的pages.json,作为router的配置,把pages.json中的路由配置转换成vue-router配置的形式。
1、根目录新建 vue.config.js 文件,写入以下内容:
//vue.config.js const TransformPages = require('uni-read-pages') const {webpack} = new TransformPages() module.exports = { configureWebpack: { plugins: [ new webpack.DefinePlugin({ ROUTES: webpack.DefinePlugin.runtimeValue(() => { const tfPages = new TransformPages({ includes: ['path', 'name', 'aliasPath'] }); return JSON.stringify(tfPages.routes) }, true ) }) ] } }
⚠️ 其中要重点关注第 10 行:
// ... includes: ['path', 'name', 'aliasPath'] // ...
includes 中包含的是router会读取pages路由中的字段名,后续如果有用到meta等路由信息,可以在 includes 里增加 'meta',在pages路由中写对应的数据,router中就可以获取得到(后面再补充案例)
2、根目录新建并写入router.js,写入以下内容:
// router.js import {RouterMount,createRouter} from 'uni-simple-router'; const router = createRouter({ platform: process.env.VUE_APP_PLATFORM, routes: [...ROUTES] }); //全局路由前置守卫 router.beforeEach((to, from, next) => { next(); }); // 全局路由后置守卫 router.afterEach((to, from) => { console.log('跳转结束') }) export { router, RouterMount }
3、main.js导入router.js并挂载
// main.js import Vue from 'vue' import App from './App' import {router,RouterMount} from './router.js' //路径换成自己的 Vue.use(router) App.mpType = 'app' const app = new Vue({ ...App }) //v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式 // #ifdef H5 RouterMount(app,router,'#app') // #endif // #ifndef H5 app.$mount(); //为了兼容小程序及app端必须这样写才有效果 // #endif
!!注意app的挂载方式,必须按照这里的写法实现!
4、重新编译运行
方法一:组件跳转
vue-router中可以通过
// main.js import Mylink from './node_modules/uni-simple-router/dist/link.vue' Vue.component('my-link',Mylink)
注册组件时注意,组件的名称不要和 pages.json 中的 easycom 属性规则冲突,否则会找easycom路径下的组件,从而找不到组件报错。
组件的完整属性,可以在文档中找到:
Router 构建选项 | uni-simple-router (hhyang.cn)
方法二:编程式导航:
在vue示例中,通过 this.$Router 获取路由对象(R必须大写),编程式导航与vue-router很接近,但仍有需要注意的地方,具体可以参考文档.
⚠️ 必须注意的点:
在vue项目中,跳转路由时经常使用name进行跳转,相比于path,name更简洁、会被改变的几率也更小。
但是在uniapp中就要留意了,如果你要使用name进行跳转,那就无法携带query参数!同理,使用path跳转也不能使用params参数
// 以下是错误的写法,name不能搭配query使用,path也不能搭配params参数使用 this.$Router.push({ name: 'newsDetail', query: { id: '123' }}) this.$Router.push({ path: '/pages/news/detail', params: { id: '123' }}) // 以下是正确的写法: this.$Router.push({ name: 'newsDetail', params: { id: '123' } }) this.$Router.push({ path: '/pages/news/detail',query: { id: '123' }})
总之:记住:path搭配query参数,name搭配params参数
在app路由栈已到达最底层时,再次点击退出程序是非常常见的功能,我们可以这样实现:
// router.js文件 import { RouterMount, createRouter, runtimeQuit } from './dist/uni-simple-router.js'; // runtimeQuit记得导入 const router = createRouter({ platform: process.env.VUE_APP_PLATFORM, routerErrorEach:({type,msg})=>{ console.log({type,msg}) // #ifdef APP-PLUS if(type===3){ router.$lockStatus=false; runtimeQuit(); } // #endif }, routes: [...ROUTES] });
routerErrorEach中,type的含义如下:
除了再次点击退出外,你还可以实现自己的逻辑,比如弹窗提示退出等:
const router = createRouter({ platform: process.env.VUE_APP_PLATFORM, routerErrorEach:({type,msg})=>{ console.log({type,msg}) // #ifdef APP-PLUS if(type===3){ router.$lockStatus=false; uni.showModal({ title: '提示', content: '您确定要退出应用吗?', success: function (res) { if (res.confirm) { plus.runtime.quit(); } } }); } // #endif }, routes: [...ROUTES] });
和vue-router一样,uniapp在页面中也能获取当前的页面路由信息,不过首字母改成了大写字母:
onLoad() { console.log(this.$Route) }
$Route 中包含了路由的基本信息以及,vue.config.js配置中includes配置的字段,和导航守卫中的to/from对象一致,利用includes配置项和导航守卫,可以实现权限校验的配置:
// router.js router.beforeEach((to, from, next) => { if (to.meta && to.meta.power === "public") { // 公共页面,不需要登录 } else { // 需要登录的页面 let isLogin = checkLogin(); // 判断是否登录 if (isLogin) { next(); } else { next({ name: "login" }) } } });
// pages.json "pages": [ { "path": "pages/login/login", "name": "login", "desc": "登录页", "meta": { "power": "public" // 不需要登录 } }, { // 需要登录 "path": "pages/my/my", "name": "login", "desc": "我的" } //... ]