Amazing 的小程序授权登录设计

930 阅读3分钟

在小程序开发中,授权登录是最常见的操作,因为很多业务是要求用户登录之后才能进行操作,那么这个流程我是怎么设计的呢,下面我就给大家唠一唠。

因为授权操作属于比较基本的功能,而且公共需求比较高,于是我把它放到了 app.js 中。在需要的地方,通过 getApp() 函数拿到 app 实例进行调用即可,使用上还是比较便利的。

下面是 app.js 中核心的代码片段:

{
  /**
   * 封装一个函数统一获取用户信息,避免直接操作 globalData
   */
  getUserInfo() {
    return this.globalData.userInfo;
  },
  /**
   * 判断是否登录
   */
  checkAuth() {
    return new Promise((resolve, reject) => {
      const userInfo = this.getUserInfo();
      userInfo ? resolve(userInfo) : reject('未登录');
    });
  },
  /**
   * 授权登录
   * 我为了简单直接用 wx.getUserProfile 进行模拟授权
   * 实际的业务情况可能还需要弹出个面板或者跳转到授权页面之类的
   */
  auth() {
    return new Promise((resolve, reject) => {
      wx.getUserProfile({
        desc: '授权登录',
        success: resolve,
        fail: reject,
      })
    }).then(({ userInfo }) => {
      this.globalData.userInfo = userInfo;
    });
  },
  /**
   * 保证一定是登录的状态
   */
  authed() {
    return this.checkAuth().catch(() => {
      return this.auth();
    });
  },
  /**
   * 退出登录
   */
  logoff() {
    return new Promise((resolve) => {
      this.globalData.userInfo = null;
      resolve();
    });
  },
  globalData: {
    userInfo: null
  }
}

主要的逻辑函数都用流行的 Promise 包裹,避免回调嵌套,组合使用特方便。在实际的业务中我会这样去使用:

{
  // tap事件处理
  async clickHandler() {
    const app = getApp();
    // 点击之后,通过 authed() 函数保证用户一定是登录状态
    // 通 Promise 链,可以很容易的实现授权之后,自动执行后续的流程
    app.authed().then(() => {
      // 身份校验通过后调用核心的逻辑 actAction
      return this.actAction();
    });
  },
  async actAction() {
    // todo 动作响应
    console.log('动作响应');
  }
}

通过 js 的方式,这样没问题,但我想 Amazing 一下:我能不能在 js 中不调用 authed() 也能实现一样的逻辑 。经过我 3S 钟的思考之后,一激动就拔下了名叫 Tom 的这根头发:

src=http___img.yao51.com_jiankangtuku_haehuewax.jpeg&refer=http___img.yao51_90_200x200.jpg

对于有点击行为的元素,我可以设计一个 Auth 组件,专门用来做登录操作,然后将这个组件嵌套在需要有点击行为的元素中。

比如:

<button class="submit-btn" bindtap="actAction">点击<Auth/></button>

让这个 Auth 像玻璃一样填充满父容器,阻止掉 Auth 组件冒泡的 tap 事件。当点击的时候实际上会先触发 Auth 组件的 tap 事件,父容器的 tap 事件并不会触发。在 Auth 组件中完成授权后,再抛出自定义的 tap 事件,父容器的 tap 事件触发,actAction 函数调用成功!非常完美

于是在我飞快的手速下,核心的代码也逐渐清晰了起来,键盘似乎也有了点儿糊味,哦!原来是 Tom 烧焦了~

Auth 组件的核心代码如下:

模版:

<-- catchtap 特别重要,这样可以捕获到点击,并且阻止冒泡给外层 -->
<view class="layer" catchtap="authCheckHandler" style="z-index:{{zIndex}};"></view>

样式表:

.layer {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

JS 部分:

Component({
  properties: {
    zIndex: {
      type: Number,
      value: 10
    }
  },
  methods: {
    authCheckHandler() {
      const app = getApp();
      app.authed().then(() => {
        this.successHandler();
      });
    },
    successHandler() {
      // 触发 tap 事件
      this.triggerEvent('tap', {}, {
        bubbles: true, // @IMPORTANT 这个地方重要的配置,允许自定义事件冒泡
      });
    },
    closeHandler() {
      // 关闭授权弹窗
      this.setData({
        visible: false,
      });
    }
  },
});

详细的代码我放在 wx-auth-demo 这个项目中,感兴趣的同学可以下载体验一下。核心的点就是通过 dom 嵌套 + 事件冒泡 ,来替换 js 逻辑中的嵌套,接下来我还是要给自己鼓会儿掌~

7321127d15d38ebd4785a3eefa70b1a5.gif