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


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 多浏览器分别判断代码
Apr 01 Javascript
JavaScript 的继承
Oct 01 Javascript
jQuery News Ticker 基于jQuery的即时新闻行情展示插件
Nov 05 Javascript
IE6背景图片不缓存问题解决方案及图片使用策略多个方法小结
May 14 Javascript
ExtJs纵坐标值重复问题的解决方法
Feb 27 Javascript
ext combobox动态加载数据库数据(附前后台)
Jun 17 Javascript
JS+CSS模拟可以无刷新显示内容的留言板实例
Mar 03 Javascript
javascript实现方法调用与方法触发小结
Mar 26 Javascript
正则表达式,替换所有HTML标签的简单实例
Nov 28 Javascript
JavaScript常见的五种数组去重的方式
Dec 15 Javascript
详解Vue组件插槽的使用以及调用组件内的方法
Nov 13 Javascript
Vue中import from的来源及省略后缀与加载文件夹问题
Feb 09 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
咖啡的化学
2021/03/03 咖啡文化
PHP动态变静态原理
2006/11/25 PHP
创建配置文件 用PHP写出自己的BLOG系统 2
2010/04/12 PHP
PHP+ajaxfileupload+jcrop插件完美实现头像上传剪裁
2014/06/09 PHP
YII框架关联查询操作示例
2019/04/29 PHP
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
js 用CreateElement动态创建标签示例
2013/11/20 Javascript
详细解密jsonp跨域请求
2015/04/15 Javascript
js实现Select列表内容自动滚动效果代码
2015/08/20 Javascript
jquery实现简单的全选和反选功能
2016/01/02 Javascript
简单实现js页面切换功能
2021/01/10 Javascript
使用开源工具制作网页验证码的方法
2016/10/17 Javascript
react中的ajax封装实例详解
2017/10/17 Javascript
JavaScript实现求最大公共子串的方法
2018/02/03 Javascript
vue 实现通过手机发送短信验证码注册功能
2018/04/19 Javascript
JavaScript canvas绘制折线图
2020/02/18 Javascript
[02:41]辉夜杯现场一家三口 “我爸玩风行 我玩血魔”
2015/12/27 DOTA
Python之PyUnit单元测试实例
2014/10/11 Python
简单介绍Python中的decode()方法的使用
2015/05/18 Python
基于Python实现的ID3决策树功能示例
2018/01/02 Python
Tornado高并发处理方法实例代码
2018/01/15 Python
Python实现二维曲线拟合的方法
2018/12/29 Python
python Pandas如何对数据集随机抽样
2019/07/29 Python
python爬虫 正则表达式解析
2019/09/28 Python
Tensorflow加载Vgg预训练模型操作
2020/05/26 Python
什么是python的函数体
2020/06/19 Python
美国批发零售网站:GearXS
2016/07/26 全球购物
加拿大著名时装品牌:SOIA & KYO
2016/08/23 全球购物
Boolean b = new Boolean(“abcde”); 会编译错误码
2013/11/27 面试题
致跳远运动员广播稿
2014/02/11 职场文书
市委召开党的群众路线教育实践活动总结大会报告
2014/10/21 职场文书
业务员辞职信范文
2015/03/02 职场文书
2015年食堂工作总结报告
2015/04/23 职场文书
新闻通讯稿模板
2015/07/22 职场文书
2015年教师节感言
2015/08/03 职场文书
小学课改工作总结
2015/08/13 职场文书