https://gitee.com/zhufan/min-router
在页面添加 navigate类型是 Array 对应值是:['navigateTo', 'switchTab', 'reLaunch', 'redirectTo']
用法
// 文件目录 pages/home/index.vue export default { navigate: ['navigateTo'] } // 会生成 navigateTo 跳转的方式 // 会生成 name 值为 所在文件夹的名称(home) export default { navigate: ['navigateTo', 'switchTab'] } // 会生成navigateTo、switchTab跳转的方式 // 会生成两条数据 // navigateTo 对应 name 值为 所在文件夹的名称(home) // switchTab 对应 name 值为 所在文件夹的名称(swhome) // 其他方式对应值 // reLaunch 对应 name 值为 所在文件夹的名称(relhome) // redirectTo 对应 name 值为 所在文件夹的名称(redhome) 复制代码
this.$minRouter.push({ // 这里的 name 对应上面生成的 name 值 name: 'home', // params 是页面传参类型最好是 Object params: { id: 1 } }) // 不传参时可以直接如下写法 this.$minRouter.push('swhome') // 获取页面参数 this.$parseURL() // 回退页面 this.$minRouter.back(-1)复制代码
项目中文件目录 router/index.js
可以设置路由拦截用法和 Vue 全局前置钩子类似
uni-app提供了路由功能来实现页面跳转,但是在使用的过程中我们还是发现有些不方便的地方,如下图:
创建一个项目
代码如下
export default { // 首页页面 index: '/pages/index/index.vue', // 我的页面 my: '/pages/my/index.vue' }复制代码
使用的时候变成这样
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view> <text class="title">{{title}}</text> </view> <button @click="openPage">跳转到我的页面</button> </view> </template> <script> import url from '../../router' export default { data() { return { title: 'index' } }, onLoad() { }, methods: { openPage () { uni.navigateTo({ url: url.my }) } } } </script>复制代码
使用的时候需要引入router.js特别麻烦,先不解决这个问题
下面来看第二和第三个问题
先看个例子
参数比较多的情况下这样确实不好操作麻烦,能不能把参数部分单独拿出来然后拼接到url上面呢?
惊奇的发现传过来的数字竟然变成字符串了,参数不能保真
第四个问题就不演示了
废话不多说了,说了这么多,相信你们也应该知道问题的所在了,下面就来解决这些问题 (渐进式讲解)
首先创建一个文件(MinRouter.js)目录结构如下
不再需要使用是引入router.js文件
import urlSet from './router'; function openPage (url) { uni.navigateTo({ url: `${urlSet[url]}` }) } export default openPage复制代码
main.js文件做如下修改
import Vue from 'vue' import App from './App' // 引入MinRouter文件 import openPage from './MinRouter' Vue.config.productionTip = false App.mpType = 'app' // 添加到全局 global.openPage = openPage const app = new Vue({ ...App }) app.$mount()复制代码
使用方式
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view> <text class="title">{{title}}</text> </view> <button @click="toPage">跳转到我的页面</button> </view> </template> <script> export default { data() { return { title: 'index' } }, onLoad() { }, methods: { toPage () { global.openPage('my') } } } </script>复制代码
第三个问题想必很多人都遇到过,本来就想传递一个number,结果不管传什么都会变成string。
有什么办法可以让数据变成字符串之后,还能还原成原来的类型?
使用JSON就能解决上面的问题了,而且也很好的解决了第二个问题
试着修改原来的代码
import urlSet from './router'; function openPage (url, query) { const queryStr = JSON.stringify(query) uni.navigateTo({ url: `${urlSet[url]}?query=${queryStr}` })} export default openPage复制代码
使用方式
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view> <text class="title">{{title}}</text> </view> <button @click="toPage">跳转到我的页面</button> </view></template><script> export default { data() { return { title: 'index' } }, onLoad() { }, methods: { toPage () { global.openPage('my', {id: 123}) } } } </script>复制代码
(=&?)等特殊字符在url上面是有特殊含义的,所以我们要把json字符串encode一下
import urlSet from './router';
function openPage (url, query) {
const queryStr = encodeURIComponent(JSON.stringify(query))
uni.navigateTo({
url: `${urlSet[url]}?query=${queryStr}`
})}
export default openPage复制代码
到此上面的问题全部解决了,但是感觉还是不太好,能不能封装成Vue插件,类似VueRouter
答案是肯定的
router.js文件改成如下
import MinRouter from './MinRouter' // 配置路由 const router = new MinRouter({ routes: [ { // 页面路径 path: 'pages/index/index', name: 'index' }, { path: 'pages/my/index', name: 'my' } ] }) export default router复制代码
main.js文件改成如下
import Vue from 'vue' import App from './App' // 引入MinRouter文件 import MinRouter from './MinRouter' // 引入router文件 import minRouter from './router' Vue.config.productionTip = false // 注册插件 Vue.use(MinRouter) App.mpType = 'app' const app = new Vue({ ...App, minRouter }) app.$mount()复制代码
上面的代码配置中已经很像VueRouter了
在MinRouter文件添加以下代码
const toString = Object.prototype.toStringfunction isObject (value) { return toString.call(value) === '[object Object]' } function isString (value) { return toString.call(value) === '[object String] '} function isDefault (value) { return value === void 0 } function install (Vue) { Vue.mixin({ beforeCreate: function () { if (!isDefault(this.$options.minRouter)) { Vue._minRouter = this.$options.minRouter } } }) Object.defineProperty(Vue.prototype, '$minRouter', { get: function () { return Vue._minRouter._router } }) } function MinRouter (options) { if (!(this instanceof MinRouter)) { throw Error("MinRouter是一个构造函数,应该用`new`关键字调用") } isDefault(options) && (options = {}) this.options = options this._router = options.routes || [] } MinRouter.install = install export default MinRouter复制代码
下面来设定openPage的参数
name:表示要跳转的页面
query:跳转页面所带的参数
调用方式: openPage({name: 跳转的页面, query: {id: 123}})复制代码
openPage函数如下
function openPage (args) { let {name, query = {}} = args let queryStr = null, path queryStr = encodeURIComponent(JSON.stringify(query)) this.$minRouter.forEach(item => { if (item.name === name) { path = item.path } }) return new Promise((resolve, reject) => { uni.navigateTo({ url: `/${path}?query=${queryStr}`, success: resolve, fail: reject }) }) }复制代码
this.$minRouter已经在上面的代码代理过来了,不要觉得奇怪,其实就是配置路由中的routes复制代码
上面的只能的路由只能使用这种方式navigateBack
这样肯定是不行的,你们可能会想在加一个参数去控制路由跳转方式,但是这样觉得不是很简便,既然openPage函数不能加,能不能在路由里面加了?
下面来修改router.js文件
import MinRouter from './MinRouter' // 配置路由 const router = new MinRouter({ routes: [ { // 页面路径 path: 'pages/index/index', // type必须是以下的值['navigateTo', 'switchTab', 'reLaunch', 'redirectTo'] // 跳转方式(默认跳转方式) type: 'navigateTo', name: 'index' }, { path: 'pages/my/index', name: 'my' } ] }) export default router复制代码
openPage函数如下
function openPage (args) { let name, query = {}, queryStr = null, path, type switch (true) { case isObject(args): ({name, query = {}} = args) break case isString(args): name = args break default: throw new Error('参数必须是对象或者字符串') } if (isObject(query)) { queryStr = encodeURIComponent(JSON.stringify(query)) } else { throw new Error('query数据必须是Object') } this.$minRouter.forEach(item => { if (item.name === name) { path = item.path type = item.type || 'navigateTo' } }) if (!['navigateTo', 'switchTab', 'reLaunch', 'redirectTo'].includes(type)) { throw new Error(`name:${name}里面的type必须是以下的值['navigateTo', 'switchTab', 'reLaunch', 'redirectTo']`) } return new Promise((resolve, reject) => { uni[type]({ url: `/${path}?query=${queryStr}`, success: resolve, fail: reject }) }) }复制代码
说了这么多还没说怎么解析路由参数了
下面函数是解析路由参数的
function parseURL () { const query = this.$root.$mp.query.query if (query) { return JSON.parse(decodeURIComponent(query)) } else { return {} } }复制代码
const toString = Object.prototype.toString function isObject (value) { return toString.call(value) === '[object Object]' } function isString (value) { return toString.call(value) === '[object String]' } function isDefault (value) { return value === void 0 } function openPage (args) { let name, query = {}, queryStr = null, path, type, isName = false switch (true) { case isObject(args): ({name, query = {}} = args) break case isString(args): name = args break default: throw new Error('参数必须是对象或者字符串') } if (isObject(query)) { queryStr = encodeURIComponent(JSON.stringify(query)) } else { throw new Error('query数据必须是Object') } this.$minRouter.forEach(item => { if (item.name === name) { path = item.path type = item.type || 'navigateTo' isName = true } }) if (!isName) { throw new Error(`没有${name}页面`) } if (!['navigateTo', 'switchTab', 'reLaunch', 'redirectTo'].includes(type)) { throw new Error(`name:${name}里面的type必须是以下的值['navigateTo', 'switchTab', 'reLaunch', 'redirectTo']`) } return new Promise((resolve, reject) => { uni[type]({ url: `/${path}?query=${queryStr}`, success: resolve, fail: reject }) }) } function parseURL () { const query = this.$root.$mp.query.query if (query) { return JSON.parse(decodeURIComponent(query)) } else { return {} }} function install (Vue) { Vue.mixin({ beforeCreate: function () { if (!isDefault(this.$options.minRouter)) { Vue._minRouter = this.$options.minRouter } } }) Object.defineProperty(Vue.prototype, '$minRouter', { get: function () { return Vue._minRouter._router } }) Object.defineProperty(Vue.prototype, '$parseURL', { get: function () { return Vue._minRouter.parseURL } }) Object.defineProperty(Vue.prototype, '$openPage', { get: function () { return Vue._minRouter.openPage } })} function MinRouter (options) { if (!(this instanceof MinRouter)) { throw Error("MinRouter是一个构造函数,应该用`new`关键字调用") } isDefault(options) && (options = {}) this.options = options this._router = options.routes || [] } MinRouter.install = install MinRouter.prototype.openPage = openPage MinRouter.prototype.parseURL = parseURL export default MinRouter复制代码
使用方式如下
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view> <text class="title">{{title}}</text> </view> <button @click="toPage">跳转到我的页面</button> </view> </template> <script> export default { data() { return { title: 'index' } }, onLoad() { // 解析路由参数 console.log(this.$parseURL()) }, methods: { toPage () { // 跳到my的页面 query是传递的参数 this.$openPage({ name: 'my', query: {id: 123} }) } } } </script>复制代码
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view> <text class="title">{{title}}</text> </view> <button @click="toPage">跳转到首页页面</button> </view> </template> <script> export default { data() { return { title: 'my' } }, onLoad() { // 解析路由参数 console.log(this.$parseURL()) }, methods: { toPage () { // 跳到index的页面 // 不传参数可以简写成如下 this.$openPage('index') } } } </script>