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


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 相关文章推荐
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
May 02 Javascript
js实现刷新iframe的方法汇总
Apr 27 Javascript
跨域请求的完美解决方法(JSONP, CORS)
Jun 12 Javascript
一种基于浏览器的自动小票机打印实现方案(js版)
Jul 26 Javascript
使用Promise链式调用解决多个异步回调的问题
Jan 15 Javascript
AngularJS ng-repeat指令中使用track by子语句解决重复数据遍历错误问题
Jan 21 Javascript
基于jQuery实现的单行公告活动轮播效果
Aug 23 jQuery
解决vue.js在编写过程中出现空格不规范报错的问题
Sep 20 Javascript
实现一个完整的Node.js RESTful API的示例
Sep 29 Javascript
用jquery获取select标签中选中的option值及文本的示例
Jan 25 jQuery
Vue-cli Eslint在vscode里代码自动格式化的方法
Feb 23 Javascript
VUE 组件转换为微信小程序组件的方法
Nov 06 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
Yii框架关联查询with用法分析
2014/12/02 PHP
PHP5.3以上版本安装ZendOptimizer扩展
2015/03/27 PHP
解决php 处理 form 表单提交多个 name 属性值相同的 input 标签问题
2017/05/11 PHP
php app支付宝回调(异步通知)详解
2018/07/25 PHP
Laravel开启跨域请求的方法
2019/10/13 PHP
ASP.NET jQuery 实例17 通过使用jQuery validation插件校验ListBox
2012/02/03 Javascript
javascript 10进制和62进制的相互转换
2014/07/31 Javascript
JS交换变量的方法
2015/01/21 Javascript
JavaScript从数组中删除指定值元素的方法
2015/03/18 Javascript
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
jQuery图片轮播滚动切换代码分享
2020/04/20 Javascript
分享网页检测摇一摇实例代码
2016/01/14 Javascript
利用jQuery实现简单的拖曳效果实例代码
2017/10/20 jQuery
vuejs实现递归树型菜单组件
2018/01/13 Javascript
浅谈mvvm-simple双向绑定简单实现
2018/04/18 Javascript
vue和webpack项目构建过程常用的npm命令详解
2018/06/15 Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
2018/09/13 Javascript
微信小程序实现单选功能
2018/10/30 Javascript
详解服务端预渲染之Nuxt(介绍篇)
2019/04/07 Javascript
Vue动态加载图片在跨域时无法显示的问题及解决方法
2020/03/10 Javascript
跟老齐学Python之深入变量和引用对象
2014/09/24 Python
python 在屏幕上逐字显示一行字的实例
2018/12/24 Python
初探利用Python进行图文识别(OCR)
2019/02/26 Python
代码实例讲解python3的编码问题
2019/07/08 Python
Python更换pip源方法过程解析
2020/05/19 Python
Opencv python 图片生成视频的方法示例
2020/11/18 Python
使用索引(Index)有哪些需要考虑的因素
2016/10/19 面试题
工程业务员岗位职责
2013/12/31 职场文书
教师个人的自我评价分享
2014/01/02 职场文书
夏季药店促销方案
2014/08/22 职场文书
公务员年终个人总结
2015/02/12 职场文书
《家庭教育》读后感3篇
2019/12/18 职场文书
在CSS中映射鼠标位置并实现通过鼠标移动控制页面元素效果(实例代码)
2021/04/22 HTML / CSS
带你学习MySQL执行计划
2021/05/31 MySQL
Win11无法安装更新补丁KB3045316怎么办 附KB3045316补丁修复教程
2022/08/14 数码科技