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


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 相关文章推荐
用JavaScript页面不刷新时全选择,全删除(GridView)
Apr 14 Javascript
使用按钮控制以何种方式打开新窗口的属性介绍
Dec 17 Javascript
JavaScript起点(严格模式深度了解)
Jan 28 Javascript
JS简单实现登陆验证附效果图
Nov 19 Javascript
jQuery选择器querySelector的使用指南
Jan 23 Javascript
浅谈Javascript线程及定时机制
Jul 02 Javascript
基于BootStrap Metronic开发框架经验小结【三】下拉列表Select2插件的使用
May 12 Javascript
JavaScript闭包实例详解
Jun 03 Javascript
JS判断微信扫码的方法
Aug 07 Javascript
JS实现图片手风琴效果
Apr 17 Javascript
js中的reduce()函数讲解
Jan 18 Javascript
Vue提供的三种调试方式你知道吗
Jan 18 Vue.js
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强制类型转换,慎用!
2013/06/06 PHP
php curl 获取https请求的2种方法
2015/04/27 PHP
详解PHP使用Redis存储session时的一个Warning定位
2017/07/05 PHP
基于逻辑运算的简单权限系统(实现) JS 版
2007/03/24 Javascript
使用JQuery和s3captche实现一个水果名字的验证
2009/08/14 Javascript
jquery显示和隐藏div特效实例
2013/02/27 Javascript
extjs表格文本启用选择复制功能具体实现
2013/10/11 Javascript
jquery 扑捉回车键事件代码
2014/04/24 Javascript
jQuery增加自定义函数的方法
2015/07/18 Javascript
批量下载对路网图片并生成html的实现方法
2016/06/07 Javascript
js实时获取窗口大小变化的实例代码
2016/11/18 Javascript
vue.js父组件使用外部对象的方法示例
2017/04/25 Javascript
zTree树形插件异步加载方法详解
2017/06/14 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
详解vue-router传参的两种方式
2018/09/10 Javascript
vue项目中,main.js,App.vue,index.html的调用方法
2018/09/20 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
2019/05/17 Javascript
vue.js实现h5机器人聊天(测试版)
2020/07/16 Javascript
Python中绑定与未绑定的类方法用法分析
2016/04/29 Python
python的构建工具setup.py的方法使用示例
2017/10/23 Python
Python3 导入上级目录中的模块实例
2019/02/16 Python
更新修改后的Python模块方法
2019/03/03 Python
python TCP包注入方式
2020/05/05 Python
加拿大便宜的隐形眼镜商店:Clearly
2016/09/15 全球购物
100%植物性、有机、即食餐:Sakara Life
2018/10/25 全球购物
台湾时尚彩瞳专门店:imeime
2019/08/16 全球购物
一些网络技术方面的面试题
2014/05/01 面试题
成都思必达公司C#程序员招聘面试题
2013/06/26 面试题
Linux文件操作命令都有哪些
2015/02/27 面试题
大专毕业生简历的自我评价
2013/10/20 职场文书
办公室岗位职责
2014/02/12 职场文书
土建施工员岗位职责
2015/04/11 职场文书
入队仪式主持词
2015/07/04 职场文书
python实现高效的遗传算法
2021/04/07 Python
php png失真的原因及解决办法
2021/11/17 PHP
Python中的程序流程控制语句
2022/02/24 Python