|
前言:
做的第一个支付宝小程序,支付宝会员日抢购的一个卡券类项目。考虑到流量会比较大,授权登陆放到用户第一次能直接访问的需要登陆的页面(或页面某个操作)进行处理。访问需要登陆的接口请求返回登陆失效的结果之后进行重新登陆,登陆成功后需要重新回到当前页面。
需求分析:
1. 登陆逻辑的处理:
用户首次访问的入口页面需要登陆的不止一个,所以登陆逻辑最好是进行统一风封装复用;
2. 登陆失效的处理:
这个支付宝小程序项目并没有登陆页,且小程序外部入口较多,所以登陆失效跳回到入口页面不仅体验不好,而且实现起来也比较复杂。
也考虑过接口登陆失效后调用登陆模块,登陆成功后回调之前的请求 A(params)=>{B(A(params)} ,但我们的接口请求是经过统一封装的,登陆失效的处理逻辑也是在封装里边的,那么回调也是在封装里边进行的,并不能同步到页面的数据进行重新赋值,也就无法重新渲染。当然,你也可以直接将登陆逻辑放到页面中去,那就是所有需要登陆的接口的处理都要放到页面中去了,那就比较麻烦了。
最后想到的最佳的解决方案就是登陆失效后重新刷新当前页面,虽说比不上重新登陆回调之前请求的体验好,但是实现上就会容易的多了,而且交互上做好登陆相关的提示,体验也还是挺不错的了。
需求实现:
1. 登陆封装:
鉴于项目中已经封装了网络请求,且登陆的相关逻辑需要引入网络请求的相关封装模块,也进行了一番探索,最终还是把登陆的逻辑封装在app.js中:
//app.js
import http from "./api/http"
App({
......
/**
* 2. 自动登录业务逻辑
*/
login: function() {
let self = this;
my.getAuthCode({
//授权类型,默认 auth_base。支持 auth_base(静默授权)/ auth_user(主动授权) / auth_zhima(芝麻信用)
scopes: ['auth_user'],
success: res => {
let authCode = res.authCode
console.log("authCode:", authCode)
if (authCode) {
// 访问用户登录接口获取usertoken
http.userLogin(authCode).then(data => {
if (!my.isEmpty(data.userToken)) {
my.setStorageSync0("usertoken", data.userToken)
if (my.getStorageSync0("currentPageUrl")) { my.reLaunch({
url: my.getStorageSync0("currentPageUrl")
}); }
} else {
console.log("userLoginError:", JSON.stringify(data))
}
})
}
},
fail: res => {
console.warn("getAuthCode:", res)
my.confirm({
title: '温馨提示',
content: '登录授权失败,您可以尝试重新授权',
confirmButtonText: '重新授权',
cancelButtonText: '取消',
success: (result) => {
if (result.confirm) {
self.login()
} else {
//取消登陆,需要返回上一页
if (my.getStorageSync0("currentPageUrl") == "/pages/my/my") {
//我的页面(tab页面需要使用relanch跳转到首页)
my.reLaunch({
url: '/pages/index/index'
})
} else {
//针对其他页面,返回上一页
my.navigateBack({
delta: 1
})
}
}
},
});
}
})
}
......
});
说明:
- 代码中的 my.isEmpty(value) getStorageSync0(key) my.setStorageSync0(key,value) 等方法均为针对支付宝小程序的特性自己封装的公共方法;
- 页面初始化接口登陆失效——这种情况可以采用静默登陆,不提示(用户看到小程序原生的授权登陆就能明白怎么回事),登陆成功之后重新加载当前页面进行初始化即可;
- 用户主动触发接口请求登陆失效——如用户单击事件调用接口,重新登陆打断了用户的操作,如果还想上边一样静默登陆不提示,那么用户会有点懵的。然而如果在重新授权登陆的过程中给出相关提示,那么用户重新执行之前的操作就好了,这样体验就好的多了。
- 关于在封装方法中重载当前页面——支付宝小程序并没有提供直接获取页面路径及参数的API,所以这个就只能在需要重载的页面保存页面的路径+参数的完整path了,下边会详细说明。
- 如果用户取消授权登陆——那么就只有让用户返回上一页了,其中Tab页需要重载首页。
2. 页面登陆及页面路径保存:
//main.js 公共方法封装
......
//将当前页面路径及参数保存到缓存中(登陆失效自动登陆后relaunch())
my.getCurrentPageUrlWithArgs=function(options) {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const url = currentPage.route
let urlWithArgs = `/${url}?`
for (let key in options) {
const value = options[key]
urlWithArgs += `${key}=${value}&`
}
urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1)
my.setStorage0("currentPageUrl",urlWithArgs)
}
//page.js import http from "../../api/http"
var app = getApp();
Page({
......
onLoad(e) {
my.getCurrentPageUrlWithArgs(e)
this.autologin()
},
autologin() {
//未登陆首次访问
if (my.isEmpty(my.getStorageSync0("usertoken"))) {
app.login()
} else {
this.getUserInfo()
}
},
......
})
说明:
- 页面onLoad的时候,调用 my.getCurrentPageUrlWithArgs() 方法保存当前页面的完整路径;
- 关于登陆,如果页面作为首次登陆的入口,如果登陆过则直接初始化,否则调用登陆方法。
3. 网络请求封装:
接口请求新增了 clickRequest 参数,有此参数,则给出相关提示,否则静默登陆不予提示:
......
const http = (params) => {
return new Promise((resolve, reject) => {
my.request({
......
success: function(res) {
//my.hideLoading()
if (res.status == 200) {
//需要登录、后端返回登录失效代码,需要自动登录然后重新加载小程序
if (!params.noNeedLogin && res.data.s == "302") {
my.removeStorageSync({ key: "usertoken" })
//根据接口的调用是否是用户主动调用来确定是否给出提示
if (params.clickRequest) {
my.toast("登陆失效,重新登陆中...", function() {
getApp().login(() => {
my.toast("登陆成功")
})
})
} else {
getApp().login()
}
return;
}
......
} else {
errorToast();
console.error(res)
}
},
fail: function(e) {
errorToast();
reject(e)
}
})
})
}
......
后记:
每新做一个项目,都会尽可能的对现有框架进行提升优化,这样不仅对当前项目的开发有帮助,也有利于以后其他类似项目的复用。力求精简代码,提升效率!有感兴趣的小伙伴可以多多留言讨论,共同探索前端技术。
个人原创博客,转载请注明来源地址:https://www.cnblogs.com/xyyt
来源:https://www.cnblogs.com/xyyt/p/11378623.html |