支付寶小程序開發——登錄失效後的交互處理

前言:前端

作的第一個支付寶小程序,支付寶會員日搶購的一個卡券類項目。考慮到流量會比較大,受權登錄放到用戶第一次能直接訪問的須要登錄的頁面(或頁面某個操做)進行處理。訪問須要登錄的接口請求返回登錄失效的結果以後進行從新登錄,登錄成功後須要從新回到當前頁面。小程序

需求分析:後端

1. 登錄邏輯的處理:api

用戶首次訪問的入口頁面須要登錄的不止一個,因此登錄邏輯最好是進行統一風封裝複用;緩存

2. 登錄失效的處理:網絡

這個支付寶小程序項目並無登錄頁,且小程序外部入口較多,因此登錄失效跳回到入口頁面不只體驗很差,並且實現起來也比較複雜。app

也考慮過接口登錄失效後調用登錄模塊,登錄成功後回調以前的請求  A(params)=>{B(A(params)} ,但咱們的接口請求是通過統一封裝的,登錄失效的處理邏輯也是在封裝裏邊的,那麼回調也是在封裝裏邊進行的,並不能同步到頁面的數據進行從新賦值,也就沒法從新渲染。固然,你也能夠直接將登錄邏輯放到頁面中去,那就是全部須要登錄的接口的處理都要放到頁面中去了,那就比較麻煩了。框架

最後想到的最佳的解決方案就是登錄失效後從新刷新當前頁面,雖然說比不上從新登錄回調以前請求的體驗好,可是實現上就會容易的多了,並且交互上作好登錄相關的提示,體驗也仍是挺不錯的了。ide

需求實現:優化

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

後記:

每新作一個項目,都會盡量的對現有框架進行提高優化,這樣不只對當前項目的開發有幫助,也有利於之後其餘相似項目的複用。力求精簡代碼,提高效率!有感興趣的小夥伴能夠多多留言討論,共同探索前端技術。

相關文章
相關標籤/搜索