小程序中的path很多都是相对路径,导航也是一样,但是导航用起来并不是很方便,特别是层级比较多的时候。当然还有从分享页打开时跳转的path,此时要是能设置绝对路径就非常方便了,直接从app.json
中拷贝过来就好。
所以做了一个router
封装,核心思想是将相对路径例如:../search/search
动态的改成../../pages/search/search
,而我们要做的就是计算并添加前面的../
举个例子:下面两种写法都是OK的
wx.navigateTo({ url: "../search/search" }) wx.navigateTo({ url: "../../pages/search/search" })
一、使用getCurrentPages()
获取当前路径path
//在 pages/home/home 中的onLoad中console.log(getCurrentPages())
打印结果如下:
getCurrentPages()结果1.png
可以看到结果数组的第一个obj的route
是我们要的,同时显示的length为1,当我navigate到下一个页面时打印的结果如下:
getCurrentPages()结果2.png
此时第二个页面处于处于结果数组的第二个obj,同时length为2.
因此,获取当前路径的方法为如下:
const length = getCurrentPages().length; const currentRoute = getCurrentPages()[length - 1].route;
二、动态添加前置../
根据相对路径我们知道,当前路径内的/
个数代表当前路径的层级,添加相同个数的../
即可到达根目录那为了实现我们的目的,可按如下操作:
//在首页使用 //path 需要导航的路径的 绝对路径 例如:pages/search/search let path = 'pages/search/search' const length = getCurrentPages().length; const currentRoute = getCurrentPages()[length - 1].route; //pages/home/home const pathIndex = currentRoute.split('/').length; //3 let url = "" for (let i = 0; i < pathIndex - 1; i++) { url += '../' } path = url + path // ../../pages/search/search
这个时候我们就获取到了我们需要路径,封装一个方法:
export function navigateTo(path) { const length = getCurrentPages().length; const currentRoute = getCurrentPages()[length - 1].route; const pathIndex = currentRoute.split('/').length; let url = "" for (let i = 0; id < pathIndex - 1; i++) { url += '../' } path = url + path wx.navigateTo({ url: path }) }
此时我们可以导入这个函数后按如下方式使用:
import { navigateTo } from "../../utils/router.js" navigateTo("pages/search/search")
三、导航已经能用了,但是数据的话,只能拼接在路径后面了,并不是很方便,所以接下来我们继续封装参数
我们拿到参数params,拿到所有的键值对,用?, = , &
手动拼接在路径后面
function joinParam(url,param) { let keys = Object.keys(params); finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url + "?"); }//关于reduce函数,这里就不讲了//实现了循环添加所有key=params[key],并在url后面拼接了'?'
此时我们的函数可以改为:
export function navigateTo(data = { path="", params } = {}) { const length = getCurrentPages().length; const currentRoute = getCurrentPages()[length - 1].route; const pathIndex = currentRoute.split('/').length; let url = "" for (let i = 0; id < pathIndex - 1; i++) { url += '../' } let path = url + data.path if (data.params) { path = this.joinParam(path, data.params) } wx.navigateTo({ url: path, }) }function joinParam(url,param) { let keys = Object.keys(params); finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url + "?"); }
使用则改为:
import { navigateTo } from "../../utils/router.js" navigateTo({ path: "pages/search/search", params: {searchId: "1010101"} })
这里只处理了单纯的路径和参数分开,后续详细版封装了所有情况,比如路径已经有部分参数,后面params又添加了参数,可至文末查看。
四、返回封装,这个就和绝对路径导航没啥关系了,但是作为router的一员,不能厚此薄彼
/** * 设置上一页面的数据,并返回 */export function navigateBack(data = {}) { if (data) { const length = getCurrentPages().length; var prePage = getCurrentPages()[length - 2] if (prePage) { prePage.setData(data) } } wx.navigateBack() }// 使用navigateBack(nickName:"我是新设置的昵称")
当我们需要回调数据至上一个页面时,我们带上参数,不需要回调时,就不写,当然参数名需要同上一个页面一致,这里就没封装跨界面返回回调数据了,用的情况比较少
五、我们还有redirectTo , switchTab , reLaunch
这些导航方法,下面分享项目中的router.js,对这些方法做了统一的封装
/** * * 这里重新封装了导航方法,navigate、redirect、switchTab、reLaunch分别对应着微信的导航方法, * 与微信提供的API不通过的是,这里参数data里面的path是静态配置,即app.json文件的页面路径; * params为链接查询参数; * @example * navigate({ * path:'pages/index/index', * params:{ * id:123 * } * });//跳转到index页面,index页面的options可以读取到id。 * */let CURRENT_ROUTE = "";/** * 封装后的 navigate 方法 * @param {path:静态路径,params: {}} */export function navigate(data = { path = "", params } = {}) { return route(data, "navigateTo") }/** * 封装后的 redirect 方法 * @param {path:静态路径,params: {}} */export function redirect(data = { path = "", params } = {}) { return route(data, "redirectTo") }/** * 封装后的 switchTab 方法 * @param {path:静态路径,params: {}} */export function switchTab(data = { path = "", params } = {}) { return route(data, "switchTab"); }/** * 封装后的 reLaunch 方法 * @param {path:静态路径,params: {}} */export function reLaunch(data = { path = "", params } = {}) { return route(data, "reLaunch"); }/** * 设置上一页面的数据,并返回 */export function navigateBack(data = {}) { if (data) { const length = getCurrentPages().length; var prePage = getCurrentPages()[length - 2] if (prePage) { prePage.setData(data) } } wx.navigateBack() }function route(data, method) { try { const length = getCurrentPages().length; const currentRoute = getCurrentPages()[length - 1].route; if (currentRoute == CURRENT_ROUTE) { //防止在用一个事件下多次导航到同一个页面 return; } CURRENT_ROUTE = currentRoute; clearCurrent(); if (data.path == currentRoute) { //不能导航到自己 return; } const pathIndex = currentRoute.split('/').length; const path = joinPath(pathIndex, data.path) const url = joinParams(data.params, path) const obj = { ...data, url }; //调用微信的router方法 wx[method].call(null, obj); } catch (e) { console.log(`error in router: +${e}`) } }function joinPath(index, url) { let str = "" for (let i = 0; i < index - 1; i++) { str += "../"; } return str + url; }function joinParams(params, url) { //没有参数,直接返回url if (!params) { return url; } let keys = Object.keys(params); let finalUrl = "" //参数没有key 返回url if (keys.length == 0) { return url; } else { //url没有拼接 ? if (url.indexOf("?") === -1) { finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url + "?"); } else { //url以 ? 号结尾 if (url.endsWith("?")) { finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url); } else { //url以 & 结尾 if (url.endsWith("&")) { finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url); } else { //直接拼接 finalUrl = keys.reduce((url, key) => { return url + key + "=" + params[key] + "&"; }, url + "&") } } } } return finalUrl.endsWith("&") ? finalUrl.slice(0, finalUrl.length - 1) : finalUrl; }function clearCurrent() { setTimeout(() => { CURRENT_ROUTE = ""; }, 0); }
希望开源这个静态导航能给大家带帮助!
作者:韦弦Zhy
链接:https://www.jianshu.com/p/ebfe6456cd6d