uniapp封装路由管理(兼容Vue2和Vue3)

1:uniapp已经有路由管理了为什么还要二次封装路由?

  • 简化配置和调用
  • 增强灵活性和可扩展性
  • 实现统一的功能和策略
  • 提升开发效率和团队协作

2. 增强灵活性和可扩展性

  • 灵活配置:二次封装允许开发者根据实际需求灵活配置路由参数,如跳转类型、页面参数等。这种灵活性使得路由管理更加符合项目的具体需求。
  • 易于扩展:随着项目的不断发展,可能需要新增或修改路由配置。通过二次封装,可以方便地扩展路由功能,无需对原有代码进行大规模修改。

2. 集中管理,简化配置

  • 统一配置:通过封装路由管理,将所有页面路由信息集中在一个地方进行配置和管理。这样不仅使得路由信息一目了然,还方便进行统一修改和维护。
  • 简化跳转 :开发者只需调用封装好的路由方法,如$openPage,而无需关心底层的路由实现细节,大大简化了页面跳转的代码。

3. 提高代码的可读性和可维护性

  • 清晰的代码结构:通过封装,将路由处理逻辑与业务逻辑分离,使得代码结构更加清晰。开发者可以更容易地理解和维护项目的导航流程。
  • 易于扩展:当需要新增或修改路由时,只需在配置中进行调整,无需修改业务代码,降低了代码耦合度,提高了可维护性。

4. 增强代码的复用性和灵活性

  • 复用性:封装的路由方法可以在项目的不同部分重复使用,无需重复编写相同的跳转逻辑。
  • 灵活性 :通过配置参数,如跳转类型(navigateToswitchTab等),可以灵活地实现不同的跳转需求,满足不同场景下的导航要求。

5. 便于实现统一的功能和策略

  • 统一处理:在路由封装中,可以方便地实现统一的路由拦截、权限校验等功能,确保所有页面跳转都遵循相同的规则。
  • 全局参数传递:通过封装,可以更方便地在页面间传递参数,实现全局状态管理,提升用户体验。

6. 提升开发效率和用户体验

  • 开发效率:封装的路由管理减少了重复代码的编写,提高了开发效率。开发者可以更快地实现页面跳转功能,专注于业务逻辑的开发。
  • 用户体验:通过统一的路由管理,可以确保页面跳转的一致性和流畅性,提升用户在应用中的导航体验。

统一管理的优势

  • 错误检查 :在处理路由配置时,添加了错误检查机制,确保每个页面都有必要的属性(如name),从而避免运行时错误。
  • 默认值处理 :在不需要指定跳转类型时,提供默认的navigateTo,简化了配置。
  • 支持SubPackages :通过处理subPackages,支持分包加载,优化了应用的性能和加载时间。

我这里简单做了一下封装有什么问题欢迎留言指正

在项目中创建min.router.config.js文件
javascript 复制代码
/**
 * min.router.config.js
 * 使用方法
 * Vue2
 * 示例:this.$openPage({name: 'my', query: {id: 123}, type: 'navigateTo'})		传参方式
 * 示例:this.$openPage('my')    不传参数可以简写
 * Vue3 setup语法糖
 * 示例:
 * import { getCurrentInstance } from 'vue';
 * const { $openPage } = getCurrentInstance().appContext.config.globalProperties;
 * $openPage({name: 'my', query: {id: 123}, type: 'navigateTo'})		传参方式
 * $openPage('my')    不传参数可以简写
 * Vue2 和 Vue3
 * 视图中可直接使用 $openPage('my')
 * @param name			字符串地址名
 * @param query			传递的参数
 * @param type			跳转的方式 ['navigateTo', 'switchTab', 'reLaunch', 'redirectTo']  不传默认navigateTo
 * this.$parseURL()		解析路由参数
 * 使用方法在接收参数页this.$parseURL(options)
 */
// #ifdef VUE3
import { getCurrentInstance } from 'vue';
// #endif

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, type, 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.$routerConfig.forEach(item => {
		if (item.name === name) {
			path = item.path;
			type = 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() {
	// #ifdef VUE2
	const query = this.$root.$mp.query.query;
	// #endif
	// #ifdef VUE3
	const query = getCurrentInstance().proxy.$root.$scope.options.query;
	// #endif
	if (query) {
		return JSON.parse(decodeURIComponent(query))
	} else {
		return {}
	}
}

function install(Vue, routerConfig) {
	if (!routerConfig || !Array.isArray(routerConfig.options.routes)) {
	  throw new Error("routerConfig 必须是一个带有 routes 属性的对象");
	}
	
	// Vue 2 和 Vue 3 的兼容混入
	Vue.mixin({
		beforeCreate: function() {
			if (!isDefault(routerConfig)) {
				Vue._routerConfig = routerConfig;
			}
		}
	})
	
	// 定义全局属性
	const globalProperties =
	  // #ifdef VUE2
	  Vue.prototype
	  // #endif
	  // #ifdef VUE3
	  Vue.config.globalProperties
	  // #endif
	  ;
	  
	Object.defineProperty(globalProperties, '$routerConfig', {
		get: function() {
			return Vue._routerConfig._router;
		}
	})
	
	Object.defineProperty(globalProperties, '$parseURL', {
		get: function() {
			return parseURL.bind(this);
		}
	})
	Object.defineProperty(globalProperties, '$openPage', {
		get: function() {
			return openPage.bind(this);
		}
	})
}

function minRouterConfig(options) {
	if (!(this instanceof minRouterConfig)) {
		throw Error("minRouterConfig是一个构造函数,应该用`new`关键字调用")
	}
	isDefault(options) && (options = {})
	this.options = options;
	this._router = options.routes || [];
}

minRouterConfig.install = install;
minRouterConfig.prototype.openPage = openPage;
minRouterConfig.prototype.parseURL = parseURL;
export default minRouterConfig;
创建router.config.js文件
javascript 复制代码
/*
 * 使用方法
 * Vue2
 * 示例:this.$openPage({name: 'my', query: {id: 123}, type: 'navigateTo'})		传参方式
 * 示例:this.$openPage('my')    不传参数可以简写 
 * 示例:<view @click="$openPage('ceshi')"></view>  奈何小程序不支持这样跳转
 * Vue3 setup语法糖
 * 示例:
 * import { getCurrentInstance } from 'vue';
 * const { $openPage } = getCurrentInstance().appContext.config.globalProperties;
 * $openPage({name: 'my', query: {id: 123}, type: 'navigateTo'})		传参方式
 * $openPage('my')    不传参数可以简写
 * Vue2 和 Vue3
 * 视图中可直接使用 $openPage('my')
 * 配置参数项说明:
 * name:可选配置 (路由名称)
 * path:必填配置 (路由地址)
 * type 跳转的方式 ['navigateTo', 'switchTab', 'reLaunch', 'redirectTo']  不传默认navigateTo
 */
import pagesJson from '@/pages.json'
import minRouterConfig from './min.router.config.js'

// 处理 pages 数组
function processPages(pages) {
	return pages.map(page => {
		if (!page.name) {
			throw Error(`Page is missing the 'name' property: ${JSON.stringify(page)}`);
		}
		
		const processedPage = {
			name: page.name,
			path: page.path
		}
		
		// 仅在 type 不存在时不添加默认值
		if(page.type) {
			processedPage.type = page.type;
		}
		
		return processedPage
	});
}

// 处理 subPackages 数组
function processSubPackages(subPackages) {
	if(!subPackages) return []
	
	let routes = [];
	subPackages.forEach(subPackage => {
		routes = routes.concat(processPages(subPackage.pages).map(page => {
			return {
				...page,
				path: subPackage.root + '/' + page.path
			};
		}));
	});
	return routes;
}

const router = new minRouterConfig({
	routes: [ // 权限路由 在main.js可实现路由拦截 所以路由都需要注册
		...processPages(pagesJson.pages),
		...processSubPackages(pagesJson.subPackages)
	]
})

export default router

router.config.js文件无需配置任何路径,均在pages.json中配置即可

最后在main.js中我们全局挂载一下

javascript 复制代码
import App from './App'

// 引入全局方法
import minRouterConfig from '@/config/min.router.config.js'
import routerConfig from '@/config/router.config.js'

// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
  ...App
})
app.$mount()
// #endif

// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  app.use(minRouterConfig, routerConfig)
  return {
    app
  }
}
// #endif

我这里是在项目根目录创建了一个config文件夹,两个文件都在config文件夹中

以上配置在uniapp框架下不管是Vue2或者是Vue3都通用

不管是Vue2的组合式API下还是Vue3的setup语法糖下都可以正常使用

在页面中使用

Vue3中 setup语法糖

html 复制代码
<template>
	<button @click="onClick">跳转我的</button>
</template>

<script setup>
	import { getCurrentInstance } from 'vue';
	
	// data数据
	const { $openPage } = getCurrentInstance().appContext.config.globalProperties;
	
	// methods方法
	const onClick = () => {
		$openPage('user')
	}
</script>

<style>
	
</style>

Vue2 组合式API

html 复制代码
<template>
	<button @click="onClick">跳转我的</button>
</template>

<script>
	export default {
		methods: {
			onClick() {
				this.$openPage('user')
			}
		}
	}
</script>

<style>
	
</style>

通用

html 复制代码
<template>
	<button @click="$openPage('user')">跳转我的</button>
</template>

<script>
	
</script>

<style>
	
</style>

以上有什么问题可以下面留言一起学习

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax