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


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 相关文章推荐
Prototype使用指南之form.js
Jan 10 Javascript
extjs 学习笔记(三) 最基本的grid
Oct 15 Javascript
基于jquery的分页控件(C#)
Jan 06 Javascript
jQuery中animate用法实例分析
Mar 09 Javascript
jQuery组件easyui基本布局实现代码
Aug 25 Javascript
最好用的Bootstrap fileinput.js文件上传组件
Dec 12 Javascript
VUE开发一个图片轮播的组件示例代码
Mar 06 Javascript
ES6正则表达式扩展笔记
Jul 25 Javascript
详谈js原型继承的一些问题
Sep 06 Javascript
详解ng-alain动态表单SF表单项设置必填和正则校验
Jun 11 Javascript
bootstrap-table后端分页功能完整实例
Jun 01 Javascript
antd中table展开行默认展示,且不需要前边的加号操作
Nov 02 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
快速配置PHPMyAdmin方法
2008/06/05 PHP
php中DOMDocument简单用法示例代码(XML创建、添加、删除、修改)
2010/12/19 PHP
PHP开发不能违背的安全规则 过滤用户输入
2011/05/01 PHP
PHP ajax 异步执行不等待执行结果的处理方法
2015/05/27 PHP
WordPress开发中自定义菜单的相关PHP函数使用简介
2016/01/05 PHP
使用Yii2实现主从数据库设置
2016/11/20 PHP
PHP7.0连接DB操作实例分析【基于mysqli】
2019/09/26 PHP
JavaScript this调用规则说明
2010/03/08 Javascript
jquery slibings选取同级其他元素的实现代码
2013/11/15 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
2014/04/12 Javascript
js实现精美的银灰色竖排折叠菜单
2015/05/16 Javascript
JavaScript中eval函数的问题
2016/01/31 Javascript
angularjs 源码解析之scope
2016/08/22 Javascript
JS表格组件BootstrapTable行内编辑解决方案x-editable
2016/09/01 Javascript
javascript 实现动态侧边栏实例详解
2016/11/11 Javascript
vue-cli入门之项目结构分析
2017/04/20 Javascript
微信小程序时间控件picker view使用详解
2018/12/28 Javascript
微信小程序BindTap快速连续点击目标页面跳转多次问题处理
2019/04/08 Javascript
inquirer.js一个用户与命令行交互的工具详解
2019/05/18 Javascript
Vue-cli3生成的Vue项目加载Mxgraph方法示例
2020/05/31 Javascript
Javascript实现单选框效果
2020/12/09 Javascript
[14:00]DOTA2国际邀请赛史上最长大战 赛后专访B神
2013/08/10 DOTA
[02:57]DOTA2亚洲邀请赛小组赛第四日 赛事回顾
2015/02/02 DOTA
基于Python爬取素材网站音频文件
2020/10/21 Python
python通过cython加密代码
2020/12/11 Python
欧舒丹比利时官网:L’OCCITANE比利时
2017/04/25 全球购物
C#笔试题集合
2013/06/21 面试题
中西医专业毕业生职业规划书
2014/02/24 职场文书
大学信息公开实施方案
2014/03/09 职场文书
关爱留守儿童倡议书
2014/04/15 职场文书
小学生运动会报道稿
2014/09/12 职场文书
医德医风自我评价
2014/09/19 职场文书
高中社区服务活动报告
2015/02/05 职场文书
2016公司新年问候语
2015/11/11 职场文书
MySQL8.0的WITH查询详情
2021/08/30 MySQL
MySQL transaction事务安全示例讲解
2022/06/21 MySQL