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


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 相关文章推荐
JavaScript CSS修改学习第三章 修改样式表
Feb 19 Javascript
兼容IE和FF的js脚本代码小结(比较常用)
Dec 06 Javascript
超级有用的13个基于jQuery的内容滚动插件和教程
Jul 31 Javascript
js判断字符长度以及中英文数字等
Dec 31 Javascript
jQuery实现默认是闭合的FAQ展开效果菜单
Sep 14 Javascript
VueJs路由跳转——vue-router的使用详解
Jan 10 Javascript
使用jQuery和ajax代替iframe的方法(详解)
Apr 12 jQuery
vue实现app页面切换动画效果实例
May 23 Javascript
详解JS函数stack size计算方法
Jun 18 Javascript
微信小程序-可移动菜单的实现过程详解
Jun 24 Javascript
Vue2.0 $set()的正确使用详解
Jul 28 Javascript
Vue.js桌面端自定义滚动条组件之美化滚动条VScroll
Dec 01 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
支持oicq头像的留言簿(二)
2006/10/09 PHP
解析CodeIgniter自定义配置文件
2013/06/18 PHP
PHP strstr 函数判断字符串是否否存在的实例代码
2013/09/28 PHP
discuz目录文件资料汇总
2014/12/30 PHP
Centos下升级php5.2到php5.4全记录(编译安装)
2015/04/03 PHP
php生成网页桌面快捷方式
2017/05/05 PHP
php实现微信发红包功能
2018/07/13 PHP
用js实现的页面关键字密度查询代码
2007/12/27 Javascript
ExtJs事件机制基本代码模型和流程解析
2010/10/24 Javascript
使用jquery与图片美化checkbox和radio控件的代码(打包下载)
2010/11/11 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
基于jquery实现的鼠标拖拽元素复制并写入效果
2011/08/23 Javascript
40个有创意的jQuery图片、内容滑动及弹出插件收藏集之一
2011/12/31 Javascript
node.js中的socket.io的广播消息
2014/12/15 Javascript
jQuery.position()方法获取不到值的安全替换方法
2015/03/13 Javascript
javascript搜索框效果实现方法
2015/05/14 Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
2016/01/18 Javascript
JavaScript控制输入框中只能输入中文、数字和英文的方法【基于正则实现】
2017/03/03 Javascript
layer插件select选中默认值的方法
2018/08/14 Javascript
微信小程序常见页面跳转操作简单示例
2019/05/01 Javascript
JS实现星星海特效
2019/12/24 Javascript
如何基于layui的laytpl实现数据绑定的示例代码
2020/04/10 Javascript
js实现文章目录索引导航(table of content)
2020/05/10 Javascript
在vue中实现禁止屏幕滚动,禁止屏幕滑动
2020/07/22 Javascript
python抓取网页中的图片示例
2014/02/28 Python
Python Web服务器Tornado使用小结
2014/05/06 Python
Python 多线程实例详解
2017/03/25 Python
Python利用matplotlib.pyplot绘图时如何设置坐标轴刻度
2018/04/09 Python
Python实现图片拼接的代码
2018/07/02 Python
python的mysql数据库建立表与插入数据操作示例
2019/09/30 Python
PyCharm GUI界面开发和exe文件生成的实现
2020/03/04 Python
CSS3教程(4):网页边框和网页文字阴影
2009/04/02 HTML / CSS
英语一分钟演讲稿
2014/04/29 职场文书
2015年科普工作总结
2015/07/23 职场文书
幼儿园中班教育随笔
2015/08/14 职场文书
2019送给家人们的中秋节祝福语
2019/08/15 职场文书