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


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 相关文章推荐
jQuery 源码分析笔记(2) 变量列表
May 28 Javascript
jquery获取div距离窗口和父级dv的距离示例
Oct 10 Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
Apr 14 Javascript
关于Javascript中defer和async的区别总结
Sep 20 Javascript
轻松搞定js表单验证
Oct 13 Javascript
BootStrap的两种模态框方式
May 10 Javascript
JS实现调用本地摄像头功能示例
May 18 Javascript
js 实现在2d平面上画8的方法
Oct 10 Javascript
JS中min函数实例讲解
Feb 18 Javascript
vuejs+element UI table表格中实现禁用部分复选框的方法
Sep 20 Javascript
JS原型和原型链原理与用法实例详解
Feb 05 Javascript
浅谈实现在线预览PDF的几种解决办法
Aug 10 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
用libTemplate实现静态网页的生成
2006/10/09 PHP
phpwind中的数据库操作类
2007/01/02 PHP
一篇不错的PHP基础学习笔记
2007/03/18 PHP
php中$美元符号与Zen Coding冲突问题解决方法分享
2014/05/28 PHP
laravel 出现command not found问题的解决方案
2019/10/23 PHP
Javascript的IE和Firefox兼容性汇编
2006/07/01 Javascript
Locate a File Using a File Open Dialog Box
2007/06/18 Javascript
JavaScript入门教程(9) Document文档对象
2009/01/31 Javascript
mailto的使用技巧分享
2012/12/21 Javascript
详解Javascript动态操作CSS
2014/12/08 Javascript
AngularJS表单编辑提交功能实例
2015/02/13 Javascript
js检测用户输入密码强度
2015/10/22 Javascript
js实现商城星星评分的效果
2015/12/29 Javascript
JS从一组数据中找到指定的单条数据的方法
2016/06/02 Javascript
深入理解vue.js双向绑定的实现原理
2016/12/05 Javascript
JS简单获取当前日期时间的方法(如:2017-03-29 11:41:10 星期四)
2017/03/29 Javascript
jQuery实现radio第一次点击选中第二次点击取消功能
2017/05/15 jQuery
安装Node.js并启动本地服务的操作教程
2018/05/12 Javascript
说说如何在Vue.js中实现数字输入组件的方法
2019/01/08 Javascript
Vue中axios拦截器如何单独配置token
2019/12/27 Javascript
6种JavaScript继承方式及优缺点(小结)
2020/02/06 Javascript
[47:21]Liquid vs TNC Supermajor 胜者组 BO3 第一场 6.4
2018/06/05 DOTA
Python中使用HTMLParser解析html实例
2015/02/08 Python
探究python中open函数的使用
2016/03/01 Python
浅谈pyhton学习中出现的各种问题(新手必看)
2017/05/17 Python
Python 实现选择排序的算法步骤
2018/04/22 Python
python与字符编码问题
2019/05/24 Python
python自动化测试无法启动谷歌浏览器问题
2019/10/10 Python
python 上下文管理器及自定义原理解析
2019/11/19 Python
英国排名第一的冲浪店:Ann’s Cottage
2020/06/21 全球购物
计划生育标语
2014/06/23 职场文书
2014企业领导班子四风对照检查材料思想汇报
2014/09/17 职场文书
稽核岗位职责范本
2015/04/13 职场文书
2019年行政人事个人工作总结范本!
2019/07/19 职场文书
使用pytorch实现线性回归
2021/04/11 Python
TS 类型收窄教程示例详解
2022/09/23 Javascript