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


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 相关文章推荐
分享20多个很棒的jQuery 文件上传插件或教程
Sep 04 Javascript
jquery和javascript的区别(常用方法比较)
Jul 04 Javascript
兼容主流浏览器的JS复制内容到剪贴板
Dec 12 Javascript
js实现固定显示区域内自动缩放图片的方法
Jul 18 Javascript
jquery使用Cookie和JSON记录用户最近浏览历史
Apr 19 Javascript
JS模拟的Map类实现方法
Jun 17 Javascript
bootstrap基本配置_动力节点Java学院整理
Jul 14 Javascript
JS实现json对象数组按对象属性排序操作示例
May 18 Javascript
使用Vue中 v-for循环列表控制按钮隐藏显示功能
Apr 23 Javascript
JavaScript工具库之Lodash详解
Jun 15 Javascript
node.js如何操作MySQL数据库
Oct 29 Javascript
JS闭包原理及其使用场景解析
Dec 03 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 文章调用类代码
2011/08/11 PHP
php中通过正则表达式下载内容中的远程图片的函数代码
2012/01/10 PHP
php 模拟post_验证页面的返回状态(实例讲解)
2013/10/28 PHP
浅析php原型模式
2014/11/25 PHP
php文件操作相关类实例
2015/06/18 PHP
详解PHP匿名函数与注意事项
2016/03/29 PHP
PHP dirname(__FILE__)原理及用法解析
2020/10/28 PHP
IE autocomplete internet explorer's autocomplete
2007/06/30 Javascript
js href的用法
2010/05/13 Javascript
SharePoint 客户端对象模型 (一) ECMA Script
2011/05/22 Javascript
JavaScript实现x秒后自动跳转到一个页面
2013/01/03 Javascript
cookie.js 加载顺序问题怎么才有效
2013/07/31 Javascript
javascript创建对象的几种模式介绍
2016/05/06 Javascript
Vue.js项目部署到服务器的详细步骤
2017/07/17 Javascript
微信小程序基于slider组件动态修改标签透明度的方法示例
2017/12/04 Javascript
vue项目环境变量配置的实现方法
2018/10/12 Javascript
JavaScript类的继承操作实例总结
2018/12/20 Javascript
微信小程序基于picker实现级联菜单
2019/02/15 Javascript
详解vue中router-link标签所必备了解的属性
2019/04/15 Javascript
JavaScript实现多张图片放大镜效果示例【不限定图片尺寸,rem单位】
2019/05/14 Javascript
vue实践---根据不同环境,自动转换请求的url地址操作
2020/09/21 Javascript
python构造icmp echo请求和实现网络探测器功能代码分享
2014/01/10 Python
Python3.6简单反射操作示例
2018/06/14 Python
Django跨域请求CSRF的方法示例
2018/11/11 Python
基于树莓派的语音对话机器人
2019/06/17 Python
CSS3感应鼠标的背景闪烁和图片缩放动画效果
2014/05/14 HTML / CSS
HTML5 Video标签的属性、方法和事件汇总介绍
2015/04/24 HTML / CSS
Burberry英国官网:英国标志性奢侈品牌
2017/03/29 全球购物
粉红色的鲸鱼:Vineyard Vines
2018/02/17 全球购物
Farnell德国:电子元器件供应商
2018/07/10 全球购物
eBay英国购物网站:eBay.co.uk
2019/06/19 全球购物
制定岗位职责的原则
2013/11/08 职场文书
机修工工作职责
2014/02/21 职场文书
求职面试个人自我评价
2014/02/28 职场文书
写求职信要注意什么问题
2014/04/12 职场文书
在校生证明
2015/06/17 职场文书