前言:
做的第一個支付寶小程序,支付寶會員日搶購的一個卡券類項目。考慮到流量會比較大,授權登陸放到用戶第一次能直接訪問的需要登陸的頁面(或頁面某個操作)進行處理。訪問需要登陸的接口請求返回登陸失效的結果之后進行重新登陸,登陸成功后需要重新回到當前頁面。
需求分析:
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) } }) }) } ......
后記:
每新做一個項目,都會盡可能的對現有框架進行提升優化,這樣不僅對當前項目的開發有幫助,也有利於以后其他類似項目的復用。力求精簡代碼,提升效率!有感興趣的小伙伴可以多多留言討論,共同探索前端技術。