浅谈下微信小程序中的路由(页面跳转、返回、刷新、页面栈)
什么是小程序里的“路由”?路由器吗?蒙蔽?好吧,在WEB应用中它其实就是分组数据包从源到目的地时,决定端到端路径的网络范围的进程;在小程序里就是设置页面的跳转,返回,自动刷新等一些功能。
而在微信小程序里,“路由”有很多限制,所以我们在开发小程序的时候,需要深入了解,否则就会掉坑里,被人笑话。
微信小程序官方文档里提供了5种:
wx.redirectTo(Object object)、
wx.reLaunch(Object object)、
wx.navigateTo(Object object)、
wx.switchTab(Object object)、
wx.navigateBack(Object object)。
接下来逐个分析下。
wx.redirectTo(Object object)
关闭当前页面,跳转到应用内的某个页面,但是不允许跳转到 tabbar 页面。
参数
Object object
属性 | 类型 | 默认值 | 是否必填 | 说明 | 支持版本 |
---|---|---|---|---|---|
url | string | 是 | 需要跳转的应用内非 tabBar 的页面的路径, 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 <code>= 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2' | ||
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
说明:这里一定要注意,在使用redirectTo()的时候,不能跳转到底部导航的页面;如果一个页面用了它来跳转,返回后不可逆,因为跳转后直接被关闭,一般用在多个页面的跳转,然后从三级页面,返回到首页【跳级返回】。
不懂?来看个例子。
比如我最近做的一个答题项目需求:首页》答题》成功。这个流程其实是可以可逆的,但是我们要求,答题成功后,返回后,直接到首页,而不是答题页面,那么在答题页面跳转到成功页面就要用到redirectTo。基本的JS写法:
wx.redirectTo({ //目的页面地址 url: 'pages/index/index', success: function(res){ }, ... })
wx.reLaunch(Object object)
关闭所有页面,打开到应用内的某个页面。
参数
Object object
属性 | 类型 | 默 认 值 | 是否 必填 | 说明 | 支持版本 |
---|---|---|---|---|---|
url | string | 是 | 需要跳转的应用内页面路径 , 路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔;如 'path?key=value&key2=value2',如果跳转的页面路径是 tabBar 页面则不能带参数 | ||
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
wx.reLaunch(),用的不是很多,他有一些版本的兼容(支持版本 >= 1.1.0),刚开始接触这个方法的时候,也试了下,点击“获取用户信息”按钮后跳转到首页,刷新首页的数据信息;我也看了网上的一些项目,也有些人类似的做法,你觉得好吗?个人觉得,关闭所有页面,重新打开跳转,不是那么明智,如果是单纯的想是刷新实时数据,可以用其他的方法,比如在onShow()里使用this.onload()等。当然啦,我们不能说它没用,不然开发出来干啥呢,根据需求来决定吧。下面分享下之前做过的一个项目对于wx.reLaunch()的应用,直接上代码:
<button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo">获取授权信息</button>
getUserInfo:function(e){ console.log('点击加载+'+e) app.globalData.userInfo = e.detail.userInfo let timer = setTimeout(function () { wx.reLaunch({ url: '/pages/index/index', fail: function () { Tools.showModal("支付界面 reLaunch调用失败,请重试"); wx.redirectTo({ url: '/pages/index/index', }) } }); }, 500) this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) }
说明:点击获取用户信息,然后跳转到首页,大家可以参考下。这里要提醒下的是,从上面的代码可以发现我们用了一个定时器(建议使用),也就是跳转到首页需要0.5S的延时,这个是针对页面的一个加载缓存需要时间,比如调用接口的数据等,当然你可以使用loading预加载。
wx.navigateTo(Object object)
保留当前页面,跳转到应用内的某个页面,但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。
参数
Object object
属性 | 类型 | 默认值 | 是否必填 | 说明 | 支持版本 |
---|---|---|---|---|---|
url | string | 是 | 需要跳转的应用内非 tabBar 的页面的路径, 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 <code>= 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2' | ||
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
wx.navigateTo()用得最多的,可逆转,使用wx.navigateTo接口跳转,原页面保留,这个是跟redirectTo()最大的区别,也就是返回的话,需要一层层的返回,不能跳级返回。具体的用法:
wx.navigateTo({ //目的页面地址 url: 'pages/logs/index', success: function(res){}, ... })
TIPS:跟页面中的A链接差不多。
wx.switchTab(Object object)
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
参数
Object object
属性 | 类型 | 默认值 | 是否必填 | 说明 | 支持版本 |
---|---|---|---|---|---|
url | string | 是 | 需要跳转的 tabBar 页面的路径(需在 app.json 的 tabBar 字段定义的页面),路径后不能带参数。 | ||
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
说明:跳转到tabBar带参数会掉坑里,需要特殊处理下。拿个网上案例来说明下:
toCategory:function(event){ var cate_id = event.currentTarget.dataset.cate_id; wx.switchTab({ url: '../category/category?cate_id='+cate_id, }); },
比如,上面一段正常的传参的代码,按照上面写的在category.js里得不到数据的;
onLoad:function(options){ console.log(options); }
所以我们需要按照官方文档,换一种思路来处理。
跳转的时候在全局变量里设置一个变量cate_id,调到category.js中后.调取全局变量里的cate_id,用完后,再把扎个变量清除掉.具体实施如下:
toCategory:function(event){ var cate_id = event.currentTarget.dataset.cate_id; app.globalData.cate_id=cate_id;//设置全局变量(app已经定义 var app=getApp()) wx.switchTab({ url: '../category/category' }); },
分类页category.js中写上这一段:
onLoad:function(options){ var that = this var cate_id=app.globalData.cate_id wx.request({ url: app.globalData.httpsurl +'public/index.php?s=product/index', data:{ cate_id:cate_id, }, success:function(res){ //清除全局变量cate_id app.globalData.cate_id="" that.setData({ alldata:res.data, }) } }) },
就可以了。
wx.navigateBack(Object object)
关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages() 获取当前的页面栈,决定需要返回几层。
参数
Object object
属性 | 类型 | 默认值 | 是否必填 | 说明 | 支持版本 |
---|---|---|---|---|---|
delta | number | 是 | 返回的页面数,如果 delta 大于现有页面数,则返回到首页。 | ||
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
注意:调用navigateTo跳转时,调用该方法的页面会被加入堆栈,而redirectTo方法则不会。见下方示例代码:
// 此处是A页面 wx.navigateTo({ url: 'B?id=1' }) // 此处是B页面 wx.navigateTo({ url: 'C?id=1' }) // 在C页面内 navigateBack,将返回A页面 wx.navigateBack({ delta: 2 })
navigateBack()也是可以携带参数返回的,我们可以自定义,如何实现呢,看下代码:
let pages = getCurrentPages();//当前页面 let prevPage = pages[pages.length-2];//上一页面 prevPage.setData({//直接给上移页面赋值 item: e.currentTarget.dataset.item, selAddress:'yes' }); wx.navigateBack({//返回 delta:1 })
回到上一页,在data里定义item,selAddress,然后在onshow里:
let pages = getCurrentPages(); let currPage = pages[pages.length-1]; if (currPage.data.selAddress==""){ that.getUserAddress(that.data.userId); }else{ that.setData({//将携带的参数赋值 address: currPage.data.item }); }
这只是一个很简单的案例,进一步的知识还要考大家去钻研了。
页面栈
大家可能对上面的一段代码提出疑问,delta是什么东东?OK,这个就相关到另外一个知识点:页面栈。
什么是页面栈呢,简单的说就是页面的层级数,大家都知道,微信小程序最多访问5层,也就是页面栈最多是5。
小程序提供了getCurrentPages()函数获取页面栈,第一个元素为首页,最后一个元素为当前页面。在上面的代码中,有提到过,比如delta:1。
使用wx.navigateTo每新开一个页面,页面栈大小加1,直到页面栈大小为5为止;如果返回页面栈会减1,当然这个只是正常逻辑,有特殊情况?往下看吧。
1、假如使用wx.navigateTo从四级页面跳转到二级页面,此时会在页面栈顶添加一个与二级页面初始状态一样的界面,但两个页面状态是独立的。页面栈大小会加1,如果页面栈大小为5,则wx.navigateTo无效。
2、假如使用wx.redirectTo从四级页面重定向到二级页面,此时会将关闭四级页面,并使用二级页面替换四级页面,但两个页面状态是独立的。此时的页面栈大小不变,请注意和使用wx.navigateTo的区别。
3、假如当前页面为五级页面,使用wx.navigateBack:
- 当delta为1,关闭五级页面,当前页面为四级页面,页面栈大小减1;
- 当delta为2,关闭依次五级页面和四级页面,当前页面为三级页面,页面栈大小减2;
- 以此类推,直到栈底为止,也就是首页。
看上去是不是很蒙蔽,不要紧,这个需要慢慢去了解,建议大家自己做个DEMO,然后每次返回或者进入下一页,打印下页面栈,您就会熟悉了。
总结
小程序应用越来越广,我们需要不断的拓展自己的技术面,才能迎合公司业务的发展速度,否则你会被淘汰。
OK,今天分享的内容有点多,初次了解的童鞋可以多花点心思去研究下,我最近做了一些小程序的项目,如果您不懂的可以咨询,不吝赐教咯,然后可以加入我们的QQ群,或者关注我们的微信公众号。
温馨提示:上述内容难免有疏漏之处,如有大神路过,请多赐教。