微信小程序前端登录模块设计

LH_S -
微信小程序前端登录模块设计
前言

微信小程序登录基本上是每个小程序都必备的功能,但是随着业务的逐渐复杂,需要考虑的情况会越来越多,所以登录功能的健壮和高效是值得重点关注的,我会按照以往经验实现一个较优雅的登录方案

基本登录流程获取微信登录凭证,通过wx.login获取,这个api会返回一个带有时效性的code发送code给服务端,这一步就是通过你和后端定义的接口发送服务端根据前端发送的code获取用户身份信息,当然这一步就不是前端的逻辑了服务端处理完后,会把用户信息和sessinId发送给前端,然后前端把需要的信息进行存储,接下来的请求就可以带着sessinId来表示身份下面是微信官方的流程图
逻辑封装

针对以上登录流程,我会封装以下几个方法供业务层调用

方法名功能getLoginCode获取微信登录凭证staticLogin静默登录singleLogin登录请求封装checkLogin判断是否登录getPhoneNum获取微信授权手机号

我习惯在promise请求中使用await-to方法,这是一个针对异步比较优雅的方案

How to write async await without try-catch blocks in Javascript

getLoginCode,一个简单的promise封装获取code

export const getLoginCode = () => {
return new Promise((resolve, reject) => {
    wx.login({
      success (res) {
        if (res.code) {
          resolve(res.code)
        } else {
          reject(res)
        }
      },
      fail(err) {
        reject(err)
      }
    })
})
}

静默登录封装,获取用户信息,并进行存储

export const staticLogin = async () => {
  // 如果已经登录,直接返回登录信息
  if (checkLogin()) {
    return getLoginInfo()
  }
  const [loginErr, loginRes] = await _to(singleLogin());
  if (loginErr) {
    throw new Error(loginErr);
  }
  // 存储用户信息,这个就根据自己的情况了,我这随便定个方法
  setLoginInfo({
    ...loginRes,
  })
  return loginRes;
}

登录请求封装,这里我是用单例模式并返回了一个promise,这样做是为了,你多次调用singleLogin时,比如快速切换页面,快速点击多个需登录区域,在数据没有返回的时候,都会等待,而不是触发多次请求

let loginInstance = null
export const singleLogin = () => {
  if (loginInstance) {
    return loginInstance
  }
  // loginReq:封装请求,包括请求后端和getLoginCode
  loginInstance = loginReq()
  loginInstance.catch((err) => {
    loginInstance = null;
    return Promise.reject(err);
  })
  return loginInstance
}

checkLogin,检查是否登录,这个就看你存储在那个地方了,视情况而定

export const checkLogin = () => {
  return Boolean(loginInfo?.sid)
}

getPhoneNum

export const getPhoneNum = async (iv, encryptedData) => {
  const [codeErr, codeRes] = await _to(getLoginCode())
  if (codeErr) {
    console.log(codeErr);
    throw new Error(codeErr);
  }
  // decrypt:请求后端
  const [phoneErr, phoneRes] = await _to(decrypt({
    iv,
    encryptedData,
    code: codeRes.code
  }))
  if (phoneErr) {
    console.log(phoneErr);
    throw new Error(phoneErr);
  }
  const phoneNumber = phoneRes.result.phoneNumber
  setLoginInfo({
    phoneNumber,
  })
  return phoneNumber
}
业务层

业务层我会在以下几个地方调用

请求前根据options判断是否需登录,并进行处理

export const REQUEST = async (requestObj) => {
 // isLogin 当前接口请求是否需要登录
 if (requestObj.isLogin && !checkLogin()) {
   const [loginErr, loginRes] = await _to(staticLogin());
   if (loginErr) {
     Toast('登录失败')
     throw new Error(loginErr);
   }
 }
 ...
}
登录按钮,这个主要用于登录失败兜底的情况,让用户主动点击,用于登录弹窗等组件,只需调用staticLogin即可

获取用户授权手机号按钮

// index.html
// 用户主动触发进行授权手机号
<button open-type="getPhoneNumber" bindgetphonenumber="bindPhoneNumber">
  <slot></slot>
</button>

// index.js
async bindPhoneNumber(e) {
 const iv = e.detail.iv;
 const encryptedData = e.detail.encryptedData;
 const [phoneErr, phoneRes] = await _to(getPhoneNum(iv, encryptedData));
 if (phoneErr) {
   Toast('获取手机号失败');
   return;
 }
 this.triggerEvent('getPhoneNumber', phoneRes);
}
页面组件,在小程序中一般都有一个页面组件,用于封装一些页面必需的功能,比如loading,导航栏,无效页面等等,登录也是必需的,所以我把登录逻辑封装到页面组件上,如果成功会通过triggerEvent触发给页面,如果失败就弹出登录弹窗,当然这种处理不太细,根据业务的不同改变相关的逻辑
在这里插入图片描述
// index.html
<view>
  ...
  <login-modal show={loginShow} {...props} />
</view>

// index.js
async created() {
  const [loginErr, loginRes] = await _to(staticLogin());
  if (loginErr) {
    Toast('登录失败');
    this.setData({
      loginShow: true,
    });
    return;
  }
  this.triggerEvent('login', loginRes);
}
还有一些不是太通用的业务组件就不叙述了...
特别申明:本文内容来源网络,版权归原作者所有,如有侵权请立即与我们联系(cy198701067573@163.com),我们将及时处理。

Tags 标签

前端微信小程序

扩展阅读

加个好友,技术交流

1628738909466805.jpg