微信小程序监听用户登录事件的实现方法


Posted in Javascript onNovember 11, 2019

最近在开发小程序,小程序既需兼顾针对新用户的内容预览,又要为注册用户提供服务,简单梳理下,基本需求如下:

  • 小程序共三个tab页,所有用户都可以浏览首页内容,了解我们可以提供的优质服务;
  • 进入其他两个页面之后,如果用户没有登录,那就显示登录按钮,如果登录了,则显示服务内容;
  • 用户在一个页面登陆之后,全局生效。

就这么个看起来很简单的需求,也经过了如下迭代:

  • 将登录状态和凭据存储在 App.globalData.authorize 中,每个需要授权的页面 onload 生命周期检查 App.globalData.authorize.authorized ,为 true 时渲染服务内容,为 false 则显示登录按钮;
  • 但如果打开了需要授权的页面 A 但是没有登录,再打开页面 B 登录,这时候回到 A 页面,登录按钮赫然在眼,这是因为 A 页面的 onload 回调函数只执行了一次;
  • 为了能在 A 页面及时共享 B 页面登录后的状态,在 A 页面的 onshow 生命周期里再获取了一次登录状态,但这样一来,打开 A 页面的时候,会出现短暂的白屏,用户甚至有可能看到按钮变成服务内容的整个过程。

翻遍小程序 API 文档 ,也没有发现用于监听登录的生命周期,就算有也用不了,因为我们有着自己的账号体系,服务端认证完毕才算真正的登录成功。

所以我决定自己包装原有的 Page 函数,添加一个 onauth 生命周期——

首先是自定义登录事件的触发与监听,官方的EventChannel 需要向后兼容,横竖是个订阅回调,那我还不如自己撸一个得了:

/**
 * @file utils/event.js
 */

/**
 * @const EMPTY_HANDLER
 * @desc 空事件回调,被取消事件将被指向此函数
 */
const EMPTY_HANDLER = () => {};

/**
 * @const eventSet - 事件监听函数集
 */
const eventSet = {
 authorize: []
};

/**
 * @function emit - 发送全局事件
 * @param {String} type - 事件类型
 * @param {Object} event - 事件对象
 */
export const emit = (type, event) => (eventSet[type] || []).forEach(item => item(Object.freeze(event)));

/**
 * @function on - 注册全局事件
 * @param {String} type - 事件类型
 * @param {Function} callback - 事件回调函数
 */
export const on = (type, callback) => {
 if (!eventSet[type]) {
  eventSet[type] = [];
 }

 if (!callback instanceof Function) {
  throw new Error('callback must be a Function!');
 }

 return eventSet[type].push(callback)
};

/**
 * @function off - 取消对某事件的监听
 * @param {String} type - 事件类型 
 * @param {Number} id - 需要取消的事件ID,即 registEvent 所返回的值
 */
export const off = (type, id) => {
 if (!eventSet[type]) return

 eventSet[type][id - 1] = EMPTY_HANDLER

 // 如果某类事件已经全被取消的话,将其置为空数组
 const noListener = !eventSet[type].reduce((pre, cur) => (cur && cur === EMPTY_HANDLER) || pre, false);
 if (noListener){
  eventSet[type] = []
 };
}

然后是对 Page 函数的魔改:

/**
 * @file utils/auth-page.js
 */

import { on } from '/event.js';

export const AuthPage = function(options){
 const { onAuth, data, onLoad } = options;
 const userInfo = {
  nickName: '', // 昵称
  account: '', // 账号
  avatar: { // 头像
   small: '',
   middle: '',
   large: ''
  },
  title: 'student', // 头衔
  phoneNumber: 0, // 电话号码
  gender: 'secret', // 性别
  'class': '' // 班级
 }

 if (options.data){
  options.data.authorized = false;
  options.data.userInfo = userInfo
 } else {
  options.data = {
   authorized: false,
   userInfo: userInfo
  }
 }

 /**
  * 仍旧调用原始的 Page 方法
  */
 Page(Object.assign(
  options,
  {
   onLoad: function () {
    const { authorize, userInfo } = getApp().globalData;

    // 执行开发者期望的 onload 事件
    onLoad instanceof Function && onLoad.bind(this)(arguments);

    // 页面初始化时,若已经授权,直接执行授权回调
    // 否则将授权回调注册为授权事件回调
    if (onAuth instanceof Function){
     if (authorize.authorized){
      onAuth.bind(this)({
       type: 'authorize',
       authorized: true,
       token: authorize.token,
       userInfo: userInfo
      });
     } else {
      on('authorize', onAuth.bind(this));
     }
    }
   }
  }
 ));
}

最后,在登录组件的里:

import { emit } from '../../utils/event.js';

wx.login({
  success: res => {
    // ...这里省略了一些复杂的登录流程
    getApp().globalData.authorize = {
      authorized: true
    };
    emit('authorize', res);
  }
})

然后,在两个需要登录的 tab 页引入 AuthPage 替换原有的 Page 函数,并在配置项里写 onAuth 回调,就可以监听登录事件了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JS删除数组元素的函数介绍
Mar 27 Javascript
window.open打开页面居中显示的示例代码
Dec 27 Javascript
js实现仿MSN带关闭功能的右下角弹窗代码
Sep 04 Javascript
jQuery多文件异步上传带进度条实例代码
Aug 16 Javascript
Bootstrap导航中表单简单实现代码
Mar 06 Javascript
微信小程序实现点击文字页面跳转功能【附源码下载】
Dec 12 Javascript
关于vue单文件中引用路径的处理方法
Jan 08 Javascript
详解Chai.js断言库API中文文档
Jan 31 Javascript
vue中使用cropperjs的方法
Mar 01 Javascript
vue如何将v-for中的表格导出来
May 07 Javascript
解决layui-open关闭自身窗口的问题
Sep 10 Javascript
小程序识别身份证,银行卡,营业执照,驾照的实现
Nov 05 Javascript
javascript 高级语法之继承的基本使用方法示例
Nov 11 #Javascript
JS 遍历 json 和 JQuery 遍历json操作完整示例
Nov 11 #jQuery
javascript/jquery实现点击触发事件的方法分析
Nov 11 #jQuery
jquery ajax 请求小技巧实例分析
Nov 11 #jQuery
javascript 对象 与 prototype 原型用法实例分析
Nov 11 #Javascript
javascript json对象小技巧之键名作为变量用法分析
Nov 11 #Javascript
Vue.js watch监视属性知识点总结
Nov 11 #Javascript
You might like
php获取参数的几种方法总结
2014/02/18 PHP
php将HTML表格每行每列转为数组实现采集表格数据的方法
2015/04/03 PHP
php实现判断访问来路是否为搜索引擎机器人的方法
2015/04/15 PHP
PHP模板引擎Smarty内建函数section,sectionelse用法详解
2016/04/11 PHP
自己动手制作jquery插件之自动添加删除行功能介绍
2011/10/14 Javascript
扩展Jquery插件处理mouseover时内部有子元素时发生样式闪烁
2011/12/08 Javascript
手机号码,密码正则验证
2014/09/04 Javascript
js获取元素外链样式的方法
2015/01/27 Javascript
jQuery通过Ajax返回JSON数据
2015/04/28 Javascript
JS判断字符串包含的方法
2015/05/05 Javascript
jQuery实现三级菜单的代码
2016/05/09 Javascript
Angular中封装fancyBox(图片预览)遇到问题小结
2017/09/01 Javascript
轻松玩转BootstrapTable(后端使用SpringMVC+Hibernate)
2017/09/06 Javascript
使用JS实现图片轮播的实例(前后首尾相接)
2017/09/21 Javascript
JS实现利用两个队列表示一个栈的方法
2017/12/13 Javascript
vue的全局提示框组件实例代码
2018/02/26 Javascript
官方推荐react-navigation的具体使用详解
2018/05/08 Javascript
少女风vue组件库的制作全过程
2019/05/15 Javascript
vue服务端渲染操作简单入门实例分析
2019/08/28 Javascript
javascript 关于赋值、浅拷贝、深拷贝的个人理解
2019/11/01 Javascript
解决vant-UI库修改样式无效的问题
2020/11/03 Javascript
[02:27]刀塔重生降临
2015/10/14 DOTA
Python 3中的yield from语法详解
2017/01/18 Python
基于django channel实现websocket的聊天室的方法示例
2019/04/11 Python
详解Python对JSON中的特殊类型进行Encoder
2019/07/15 Python
python 子类调用父类的构造函数实例
2020/03/12 Python
Python configparser模块应用过程解析
2020/08/14 Python
下述程序的作用是计算机数组中的最大元素值及其下标
2012/11/26 面试题
12岁生日感言
2014/01/21 职场文书
淘宝店铺营销方案
2014/02/13 职场文书
市场营销策划方案
2014/06/11 职场文书
2015年医药代表工作总结
2015/04/25 职场文书
七一慰问简报
2015/07/20 职场文书
详解Java七大阻塞队列之SynchronousQueue
2021/09/04 Java/Android
Python如何使用循环结构和分支结构
2022/04/13 Python
Linux中sftp常用命令整理
2022/06/28 Servers