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