支付宝小程序开发——登陆失效后的交互处理

前言:

做的第一个支付宝小程序,支付宝会员日抢购的一个卡券类项目。考虑到流量会比较大,授权登陆放到用户第一次能直接访问的需要登陆的页面(或页面某个操作)进行处理。访问需要登陆的接口请求返回登陆失效的结果之后进行重新登陆,登陆成功后需要重新回到当前页面。

需求分析:

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/p/11378623.html