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


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 对Select的操作备忘记录
Jul 04 Javascript
关于js日期转化为毫秒数“节省20%的效率和和节省9个字符“问题
Mar 01 Javascript
js键盘事件的keyCode
Jul 29 Javascript
Javascript保存网页为图片借助于html2canvas库实现
Sep 05 Javascript
vue学习笔记之vue1.0和vue2.0的区别介绍
May 17 Javascript
javascript将list转换成树状结构的实例
Sep 08 Javascript
layui实现checkbox的目录树tree的例子
Sep 12 Javascript
vue数据响应式原理知识点总结
Feb 16 Javascript
electron 如何将任意资源打包的方法步骤
Apr 16 Javascript
vue开发简单上传图片功能
Jun 30 Javascript
js实现验证码功能
Jul 24 Javascript
JS前端轻量fabric.js系列之画布初始化
Aug 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 MVC模式在网站架构中的实现分析
2010/03/04 PHP
PHP垃圾回收机制简单说明
2010/07/22 PHP
PHP使用GIFEncoder类生成gif动态滚动字幕
2014/07/01 PHP
CodeIgniter实现从网站抓取图片并自动下载到文件夹里的方法
2015/06/17 PHP
给Javascript数组插入一条记录的代码
2007/08/30 Javascript
一些主流JS框架中DOMReady事件的实现小结
2011/02/12 Javascript
js获取单选框或复选框值及操作
2012/12/18 Javascript
JS/FLASH实现复制代码到剪贴板(兼容所有浏览器)
2013/05/27 Javascript
javascript与jquery中跳出循环的区别总结
2013/11/04 Javascript
jquery1.10给新增元素绑定事件的方法
2014/03/06 Javascript
关闭时刷新父窗口两种方法
2014/05/07 Javascript
jQuery针对各类元素操作基础教程
2014/08/29 Javascript
node.js读取文件到字符串的方法
2015/06/29 Javascript
jQuery实现下拉菜单(内容为时间)的实时更新及图表的随动更新的方法
2016/07/07 Javascript
Vue2.0表单校验组件vee-validate的使用详解
2017/05/02 Javascript
js中json对象和字符串的理解及相互转化操作实现方法
2017/09/22 Javascript
微信小程序实现左侧滑动导航栏
2020/04/08 Javascript
[51:11]2014 DOTA2国际邀请赛中国区预选赛5.21 LGD-CDEC VS DT
2014/05/22 DOTA
python实现的一只从百度开始不断搜索的小爬虫
2013/08/13 Python
详解python之多进程和进程池(Processing库)
2017/06/09 Python
python DataFrame 修改列的顺序实例
2018/04/10 Python
Numpy中转置transpose、T和swapaxes的实例讲解
2018/04/17 Python
Django xadmin开启搜索功能的实现
2019/11/15 Python
Python semaphore evevt生产者消费者模型原理解析
2020/03/18 Python
django执行原始查询sql,并返回Dict字典例子
2020/04/01 Python
python怎么自定义捕获错误
2020/06/29 Python
python3判断IP地址的方法
2021/03/04 Python
css3实现图片遮罩效果鼠标hover以后出现文字
2013/11/05 HTML / CSS
使用html5 canvas创建太空游戏的示例
2014/05/08 HTML / CSS
HTML5中的Web Notification桌面右下角通知功能的实现
2018/04/19 HTML / CSS
医药销售求职信范文
2014/02/01 职场文书
承诺书格式
2014/06/03 职场文书
2015年党总支工作总结
2015/05/25 职场文书
2015秋季开学典礼新闻稿
2015/07/17 职场文书
win10清理dns缓存
2022/04/19 数码科技
Python find()、rfind()方法及作用
2022/12/24 Python