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


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 相关文章推荐
会自动逐行上升的文本框
Jun 30 Javascript
innerHTML,outerHTML,innerTEXT三者之间的区别
Jan 28 Javascript
ExtJS下grid的一些属性说明
Dec 13 Javascript
JS小游戏之极速快跑源码详解
Sep 25 Javascript
jQuery插件slicebox实现3D动画图片轮播切换特效
Apr 12 Javascript
jquery实现隐藏在左侧的弹性弹出菜单效果
Sep 18 Javascript
在Docker快速部署Node.js应用的详细步骤
Sep 02 Javascript
js判断是否是手机页面
Mar 17 Javascript
js案例之鼠标跟随jquery版(实例讲解)
Jul 21 jQuery
node+express+ejs使用模版引擎做的一个示例demo
Sep 18 Javascript
javascript单张多张图无缝滚动实例代码
May 10 Javascript
如何正确解决VuePress本地访问出现资源报错404的问题
Dec 03 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
学习使用curl采集curl使用方法
2012/01/11 PHP
php中配置文件操作 如config.php文件的读取修改等操作
2012/07/07 PHP
关于js和php对url编码的处理方法
2014/03/04 PHP
ci检测是ajax还是页面post提交数据的方法
2014/11/10 PHP
基于jquery实现的服务器验证控件的启用和禁用代码
2010/04/27 Javascript
基于jquery的loading效果实现代码
2010/11/05 Javascript
基于jquery的点击链接插入链接内容的代码
2012/07/31 Javascript
jQuery在html有效在jsp无效的原因及解决方法
2013/08/02 Javascript
JavaScript实现广告的关闭与显示效果实例
2015/07/02 Javascript
不定义JQuery插件 不要说会JQuery
2016/03/07 Javascript
微信小程序 swiper组件构建轮播图的实例
2017/09/20 Javascript
vue2.0使用swiper组件实现轮播效果
2017/11/27 Javascript
JS实现验证码倒计时的注册页面
2018/01/02 Javascript
细述Javascript的加法运算符的具体使用
2019/10/18 Javascript
vue中js判断长时间不操作界面自动退出登录(推荐)
2020/01/22 Javascript
浅谈Vue3.0新版API之composition-api入坑指南
2020/04/30 Javascript
Python解析json文件相关知识学习
2016/03/01 Python
Python基于回溯法子集树模板解决找零问题示例
2017/09/11 Python
python实现百万答题自动百度搜索答案
2018/01/16 Python
Flask实现图片的上传、下载及展示示例代码
2018/08/03 Python
如何通过50行Python代码获取公众号全部文章
2019/07/12 Python
解决pyinstaller打包运行程序时出现缺少plotly库问题
2020/06/02 Python
python3 中时间戳、时间、日期的转换和加减操作
2020/07/14 Python
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
2014/05/07 HTML / CSS
详解如何使用CSS3中的结构伪类选择器和伪元素选择器
2020/01/06 HTML / CSS
HTML5 中新的全局属性(整理)
2013/07/31 HTML / CSS
日本最大的药妆连锁店:Matsukiyo松本清药妆店
2017/11/23 全球购物
德国最大的设计师鞋网上商店:Budapester
2017/12/07 全球购物
Hanro官网:奢华男士和女士内衣、睡衣和家居服
2018/10/25 全球购物
人民教师求职自荐信
2014/03/12 职场文书
2014学习十八届四中全会精神思想汇报范文
2014/10/23 职场文书
接收函格式
2015/01/30 职场文书
小学生心理健康活动总结
2015/05/08 职场文书
2019年公司卫生管理制度样本
2019/08/21 职场文书
Android使用EventBus发送消息,Fragment中接收消息的方法会执行多次
2022/04/24 Java/Android
ECharts transform数据转换和dataZoom在项目中使用
2022/12/24 Javascript