WeChat applet to listen for user login events

Recently, in the development of applets, which take into account both content preview for new users and services for registered users, the basic requirements are as follows:

  1. The applet has three tab pages, so all users can browse the contents of the first page to see the quality of services we can provide.
  2. After entering the other two pages, if the user is not logged in, the logon button is displayed, and if the user is logged in, the service content is displayed.
  3. The user logs on to a page and takes effect globally.

This seemingly simple requirement has undergone the following iterations:

  1. Store login status and credentials in App.globalData.authorize, check the onload life cycle of each page that needs authorization, render service content for true, and display login button for false;
  2. But if you open page A that needs authorization but don't sign in, and then open page B to sign in, you will return to page A and the login button will be in your eyes, because the onload callback function of page A only executes once;
  3. In order to share the status of B page login in A page in time, we get another login status in the onshow life cycle of A page. However, when opening A page, there will be a short white screen, and users may even see the whole process of button becoming service content.

Looking through the applet API documentation, I don't find the life cycle to monitor login, even if it is not, because we have our own account system, and the server certification is complete before the real login success.
So I decided to wrap the original Page function myself and add an onauth lifecycle:

First, customize the triggering and monitoring of login events, officially EventChannel Need backward compatibility, vertical is a subscription callback, so I'm not as good as myself:

 * @file utils/event.js

 * @desc Empty event callback, cancelled event will be pointed to this function
const EMPTY_HANDLER = () => {};

 * @const eventSet - Event Listening Function Set
const eventSet = {
  authorize: []

 * @function emit - Send global events
 * @param {String} type - Event Type
 * @param {Object} event - Event Object
export const emit = (type, event) => (eventSet[type] || []).forEach(item => item(Object.freeze(event)));

 * @function on - Register Global Events
 * @param {String} type - Event Type
 * @param {Function} callback - event callbacks
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 - Cancel listening to an event
 * @param {String} type - Event Type 
 * @param {Number} id - Event ID to cancel, the value returned by registEvent
export const off = (type, id) => {
  if (!eventSet[type]) return

  eventSet[type][id - 1] = EMPTY_HANDLER

  // If an event of a type has been completely cancelled, set it to an empty array
  const noListener = !eventSet[type].reduce((pre, cur) => (cur && cur === EMPTY_HANDLER) || pre, false);
  if (noListener){
    eventSet[type] = []

Then there's a magic change to the Page function:

 * @file utils/auth-page.js

import { on } from '/event.js';

export const AuthPage = function(options){
  const { onAuth, data, onLoad } = options;
  const userInfo = {
    nickName: '',  // Nickname?
    account: '',  // Account number
    avatar: {  // Head portrait
      small: '',
      middle: '',
      large: ''
    title: 'student',  // Title
    phoneNumber: 0,  // Phone number
    gender: 'secret',  // Gender
    'class': ''  // class

  if (options.data){
    options.data.authorized = false;
    options.data.userInfo = userInfo
  } else {
    options.data = {
      authorized: false,
      userInfo: userInfo

   * Still calling the original Page method
      onLoad: function () {
        const { authorize, userInfo } = getApp().globalData;

        // Execute the onload event expected by the developer
        onLoad instanceof Function && onLoad.bind(this)(arguments);

        // When the page is initialized, if authorized, perform the authorization callback directly
        // Otherwise, the authorization callback will be registered as an authorization event callback
        if (onAuth instanceof Function){
          if (authorize.authorized){
              type: 'authorize',
              authorized: true,
              token: authorize.token,
              userInfo: userInfo
          } else {
            on('authorize', onAuth.bind(this));

Finally, in the login component:

import { emit } from '../../utils/event.js';

    success: res => {
        // ...some complicated login processes are omitted here
        getApp().globalData.authorize = {
            authorized: true
        emit('authorize', res);

Then, you can listen for login events by introducing AuthPage in two tab pages that require login to replace the original Page function and writing onAuth callbacks in the configuration item.

Keywords: Javascript

Added by RyanDev on Mon, 11 Nov 2019 06:10:42 +0200