zoukankan      html  css  js  c++  java
  • 支付宝小程序开发——登陆失效后的交互处理

    前言:

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

    需求分析:

    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)
                }
            })
        })
    }
    ......

    后记:

    每新做一个项目,都会尽可能的对现有框架进行提升优化,这样不仅对当前项目的开发有帮助,也有利于以后其他类似项目的复用。力求精简代码,提升效率!有感兴趣的小伙伴可以多多留言讨论,共同探索前端技术。

  • 相关阅读:
    重载运算符 && 构造函数 的写法
    2019 ICPC Asia Xuzhou Regional
    中国剩余定理
    求逆元
    Exgcd
    Leading Robots
    大家好
    AtCoder Grand Contest 047 部分题解
    CodeForces 1389E Calendar Ambiguity 题解
    CodeForces 1380F Strange Addition 题解
  • 原文地址:https://www.cnblogs.com/xyyt/p/11378623.html
Copyright © 2011-2022 走看看