支付宝小程序开发——登陆失效后的交互处理
<p><strong>前言:</strong></p><p>做的第一个支付宝小程序,支付宝会员日抢购的一个卡券类项目。考虑到流量会比较大,授权登陆放到用户第一次能直接访问的需要登陆的页面(或页面某个操作)进行处理。访问需要登陆的接口请求返回登陆失效的结果之后进行重新登陆,登陆成功后需要重新回到当前页面。</p>
<p><strong>需求分析:</strong></p>
<p>1. 登陆逻辑的处理:</p>
<p>用户首次访问的入口页面需要登陆的不止一个,所以登陆逻辑最好是进行统一风封装复用;</p>
<p>2. 登陆失效的处理:</p>
<p>这个支付宝小程序项目并没有登陆页,且小程序外部入口较多,所以登陆失效跳回到入口页面不仅体验不好,而且实现起来也比较复杂。</p>
<p>也考虑过接口登陆失效后调用登陆模块,登陆成功后回调之前的请求 <span class="cnblogs_code">A(params)=>{B(A(params)}</span> ,但我们的接口请求是经过统一封装的,登陆失效的处理逻辑也是在封装里边的,那么回调也是在封装里边进行的,并不能同步到页面的数据进行重新赋值,也就无法重新渲染。当然,你也可以直接将登陆逻辑放到页面中去,那就是所有需要登陆的接口的处理都要放到页面中去了,那就比较麻烦了。</p>
<p>最后想到的最佳的解决方案就是登陆失效后重新刷新当前页面,虽说比不上重新登陆回调之前请求的体验好,但是实现上就会容易的多了,而且交互上做好登陆相关的提示,体验也还是挺不错的了。</p>
<p><strong>需求实现:</strong></p>
<p><strong>1. 登陆封装:</strong></p>
<p>鉴于项目中已经封装了网络请求,且登陆的相关逻辑需要引入网络请求的相关封装模块,也进行了一番探索,最终还是把登陆的逻辑封装在app.js中:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">app.js</span>
import http from "./api/http"<span style="color: rgba(0, 0, 0, 1)">
App({
......
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 2. 自动登录业务逻辑
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
login: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
let self </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
my.getAuthCode({
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">授权类型,默认 auth_base。支持 auth_base(静默授权)/ auth_user(主动授权) / auth_zhima(芝麻信用)</span>
scopes: ['auth_user'<span style="color: rgba(0, 0, 0, 1)">],
success: res </span>=><span style="color: rgba(0, 0, 0, 1)"> {
let authCode </span>=<span style="color: rgba(0, 0, 0, 1)"> res.authCode
console.log(</span>"authCode:"<span style="color: rgba(0, 0, 0, 1)">, authCode)
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (authCode) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 访问用户登录接口获取usertoken</span>
http.userLogin(authCode).then(data =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">my.isEmpty(data.userToken)) {
my.setStorageSync0(</span>"usertoken"<span style="color: rgba(0, 0, 0, 1)">, data.userToken)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (my.getStorageSync0("currentPageUrl"<span style="color: rgba(0, 0, 0, 1)">)) {<br> <strong>my.reLaunch({
url: my.getStorageSync0(</strong></span><strong>"currentPageUrl"</strong><span style="color: rgba(0, 0, 0, 1)"><strong>)
});</strong><br> }
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"userLoginError:"<span style="color: rgba(0, 0, 0, 1)">, JSON.stringify(data))
}
})
}
},
fail: res </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.warn(</span>"getAuthCode:"<span style="color: rgba(0, 0, 0, 1)">, res)
my.confirm({
title: </span>'温馨提示'<span style="color: rgba(0, 0, 0, 1)">,
content: </span>'登录授权失败,您可以尝试重新授权'<span style="color: rgba(0, 0, 0, 1)">,
confirmButtonText: </span>'重新授权'<span style="color: rgba(0, 0, 0, 1)">,
cancelButtonText: </span>'取消'<span style="color: rgba(0, 0, 0, 1)">,
success: (result) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (result.confirm) {
self.login()
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><strong><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">取消登陆,需要返回上一页</span></strong>
<span style="color: rgba(0, 0, 255, 1)">if</span> (my.getStorageSync0("currentPageUrl") == "/pages/my/my"<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">我的页面(tab页面需要使用relanch跳转到首页)</span>
<strong><span style="color: rgba(0, 0, 0, 1)"> my.reLaunch({
url: </span>'/pages/index/index'</strong><span style="color: rgba(0, 0, 0, 1)"><strong>
})</strong>
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">针对其他页面,返回上一页</span>
<strong><span style="color: rgba(0, 0, 0, 1)"> my.navigateBack({
delta: </span>1</strong><span style="color: rgba(0, 0, 0, 1)"><strong>
})</strong>
}
}
},
});
}
})
}
......</span><span style="color: rgba(0, 0, 0, 1)">
});
</span></pre>
</div>
<p>说明:</p>
<ul>
<li>代码中的 <span class="cnblogs_code">my.isEmpty(value) <span class="cnblogs_code">getStorageSync0(key) <span class="cnblogs_code">my.setStorageSync0(key,value) 等方法均为针对支付宝小程序的特性自己封装的公共方法;</span></span></span></li>
<li>页面初始化接口登陆失效——这种情况可以采用静默登陆,不提示(用户看到小程序原生的授权登陆就能明白怎么回事),登陆成功之后重新加载当前页面进行初始化即可;</li>
<li>用户主动触发接口请求登陆失效——如用户单击事件调用接口,重新登陆打断了用户的操作,如果还想上边一样静默登陆不提示,那么用户会有点懵的。然而如果在重新授权登陆的过程中给出相关提示,那么用户重新执行之前的操作就好了,这样体验就好的多了。</li>
<li>关于在封装方法中重载当前页面——支付宝小程序并没有提供直接获取页面路径及参数的API,所以这个就只能在需要重载的页面保存页面的路径+参数的完整path了,下边会详细说明。</li>
<li>如果用户取消授权登陆——那么就只有让用户返回上一页了,其中Tab页需要重载首页。</li>
</ul>
<p><strong>2. 页面登陆及页面路径保存:</strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">main.js 公共方法封装</span>
<span style="color: rgba(0, 0, 0, 1)">......
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将当前页面路径及参数保存到缓存中(登陆失效自动登陆后relaunch())</span>
my.getCurrentPageUrlWithArgs=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(options) {
const pages </span>=<span style="color: rgba(0, 0, 0, 1)"> getCurrentPages()
const currentPage </span>= pages
const url </span>=<span style="color: rgba(0, 0, 0, 1)"> currentPage.route
let urlWithArgs </span>= `/${url}?`
<span style="color: rgba(0, 0, 255, 1)">for</span> (let key <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> options) {
const value </span>=<span style="color: rgba(0, 0, 0, 1)"> options
urlWithArgs </span>+= `${key}=${value}&<span style="color: rgba(0, 0, 0, 1)">`
}
urlWithArgs </span>= urlWithArgs.substring(0, urlWithArgs.length - 1<span style="color: rgba(0, 0, 0, 1)">)
my.setStorage0(</span>"currentPageUrl"<span style="color: rgba(0, 0, 0, 1)">,urlWithArgs)
}</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(51, 153, 102, 1)">//page.js</span><br>import http from "../../api/http"
<span style="color: rgba(0, 0, 255, 1)">var</span> app =<span style="color: rgba(0, 0, 0, 1)"> getApp();
Page({
......
onLoad(e) {
my.getCurrentPageUrlWithArgs(e)
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.autologin()
},
autologin() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">未登陆首次访问</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (my.isEmpty(my.getStorageSync0("usertoken"<span style="color: rgba(0, 0, 0, 1)">))) {
app.login(</span><span style="color: rgba(0, 0, 0, 1)">)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getUserInfo()
}
},
......
})</span></pre>
</div>
<p>说明:</p>
<ul>
<li>页面onLoad的时候,调用 <span class="cnblogs_code">my.getCurrentPageUrlWithArgs()</span> 方法保存当前页面的完整路径;</li>
<li>关于登陆,如果页面作为首次登陆的入口,如果登陆过则直接初始化,否则调用登陆方法。</li>
</ul>
<p><strong>3. 网络请求封装:</strong></p>
<p>接口请求新增了 <span class="cnblogs_code">clickRequest</span> 参数,有此参数,则给出相关提示,否则静默登陆不予提示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">......
const http </span>= (params) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Promise((resolve, reject) =><span style="color: rgba(0, 0, 0, 1)"> {
my.request({
......
success: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(res) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">my.hideLoading()</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (res.status == 200<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需要登录、后端返回登录失效代码,需要自动登录然后重新加载小程序</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!params.noNeedLogin && res.data.s == "302"<span style="color: rgba(0, 0, 0, 1)">) {
my.removeStorageSync({ key: </span>"usertoken"<span style="color: rgba(0, 0, 0, 1)"> })
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据接口的调用是否是用户主动调用来确定是否给出提示</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (params.clickRequest) {
my.toast(</span>"登陆失效,重新登陆中...", <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
getApp().login(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
my.toast(</span>"登陆成功"<span style="color: rgba(0, 0, 0, 1)">)
})
})
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
getApp().login()
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
......
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
errorToast();
console.error(res)
}
},
fail: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(e) {
errorToast();
reject(e)
}
})
})
}
......</span></pre>
</div>
<p><strong>后记:</strong></p>
<p>每新做一个项目,都会尽可能的对现有框架进行提升优化,这样不仅对当前项目的开发有帮助,也有利于以后其他类似项目的复用。力求精简代码,提升效率!有感兴趣的小伙伴可以多多留言讨论,共同探索前端技术。</p>
</div>
<div id="MySignature" role="contentinfo">
个人原创博客,转载请注明来源地址:https://www.cnblogs.com/xyyt<br><br>
来源:https://www.cnblogs.com/xyyt/p/11378623.html
頁:
[1]