逆风翱翔 發表於 2019-8-19 17:55:00

支付宝小程序开发——登陆失效后的交互处理

<p><strong>前言:</strong></p>
<p>做的第一个支付宝小程序,支付宝会员日抢购的一个卡券类项目。考虑到流量会比较大,授权登陆放到用户第一次能直接访问的需要登陆的页面(或页面某个操作)进行处理。访问需要登陆的接口请求返回登陆失效的结果之后进行重新登陆,登陆成功后需要重新回到当前页面。</p>
<p><strong>需求分析:</strong></p>
<p>1. 登陆逻辑的处理:</p>
<p>用户首次访问的入口页面需要登陆的不止一个,所以登陆逻辑最好是进行统一风封装复用;</p>
<p>2. 登陆失效的处理:</p>
<p>这个支付宝小程序项目并没有登陆页,且小程序外部入口较多,所以登陆失效跳回到入口页面不仅体验不好,而且实现起来也比较复杂。</p>
<p>也考虑过接口登陆失效后调用登陆模块,登陆成功后回调之前的请求 &nbsp;<span class="cnblogs_code">A(params)=&gt;{B(A(params)}</span>&nbsp;,但我们的接口请求是经过统一封装的,登陆失效的处理逻辑也是在封装里边的,那么回调也是在封装里边进行的,并不能同步到页面的数据进行重新赋值,也就无法重新渲染。当然,你也可以直接将登陆逻辑放到页面中去,那就是所有需要登陆的接口的处理都要放到页面中去了,那就比较麻烦了。</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>=&gt;<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 =&gt;<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>=&gt;<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>=&gt;<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>代码中的&nbsp;<span class="cnblogs_code">my.isEmpty(value)&nbsp;&nbsp;<span class="cnblogs_code">getStorageSync0(key)&nbsp;&nbsp;<span class="cnblogs_code">my.setStorageSync0(key,value)&nbsp;等方法均为针对支付宝小程序的特性自己封装的公共方法;</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}&amp;<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的时候,调用&nbsp;<span class="cnblogs_code">my.getCurrentPageUrlWithArgs()</span>&nbsp;方法保存当前页面的完整路径;</li>
<li>关于登陆,如果页面作为首次登陆的入口,如果登陆过则直接初始化,否则调用登陆方法。</li>
</ul>
<p><strong>3. 网络请求封装:</strong></p>
<p>接口请求新增了&nbsp;<span class="cnblogs_code">clickRequest</span>&nbsp;参数,有此参数,则给出相关提示,否则静默登陆不予提示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">......
const http </span>= (params) =&gt;<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) =&gt;<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 &amp;&amp; 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>=&gt;<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]
查看完整版本: 支付宝小程序开发——登陆失效后的交互处理