Advanced event communication system for inter-page and inter-component messaging with caching, lifecycle management, and navigation integration.
Core class for creating isolated event communication channels between pages and components.
/**
* Event channel for isolated communication between pages/components
* @param id - Unique channel identifier
* @param events - Initial event listeners (optional)
*/
class EventChannel {
constructor(id: number, events?: Record<string, Function>);
/**
* Emit event to all listeners
* @param eventName - Name of the event to emit
* @param args - Arguments to pass to event listeners
*/
emit(eventName: string, ...args: any[]): void;
/**
* Register persistent event listener
* @param eventName - Name of the event to listen for
* @param fn - Event handler function
*/
on(eventName: string, fn: Function): void;
/**
* Register one-time event listener
* @param eventName - Name of the event to listen for
* @param fn - Event handler function (automatically removed after first call)
*/
once(eventName: string, fn: Function): void;
/**
* Remove event listener(s)
* @param eventName - Name of the event
* @param fn - Specific handler to remove (optional, removes all if not provided)
*/
off(eventName: string, fn?: Function): void;
}Usage Examples:
// Create event channel with initial events
const eventChannel = new EventChannel(1, {
dataUpdate: (data) => {
console.log('Initial data update handler:', data);
},
statusChange: (status) => {
console.log('Status changed to:', status);
}
});
// Register additional event listeners
eventChannel.on('userAction', (action, userId) => {
console.log(`User ${userId} performed action: ${action}`);
updateUserActivity(userId, action);
});
// Register one-time listener
eventChannel.once('initialization', () => {
console.log('Channel initialized - this runs only once');
performInitialSetup();
});
// Emit events
eventChannel.emit('userAction', 'login', 12345);
eventChannel.emit('dataUpdate', { timestamp: Date.now(), data: {...} });
eventChannel.emit('statusChange', 'active');
// Remove specific listener
const specificHandler = (data) => console.log('Specific handler:', data);
eventChannel.on('dataUpdate', specificHandler);
eventChannel.off('dataUpdate', specificHandler); // Remove only this handler
// Remove all listeners for an event
eventChannel.off('userAction'); // Removes all userAction listenersFunctions for creating, managing, and retrieving event channels.
/**
* Create and initialize a new event channel
* @param events - Initial event listeners (optional)
* @param cache - Whether to cache the channel for later retrieval (default: true)
* @returns EventChannel instance
*/
function initEventChannel(events?: Record<string, Function>, cache?: boolean): EventChannel;
/**
* Retrieve and consume a cached event channel
* @param id - Channel ID to retrieve (optional, returns next available if not provided)
* @returns EventChannel instance or undefined
*/
function getEventChannel(id?: number): EventChannel | undefined;Usage Examples:
import { initEventChannel, getEventChannel } from "@dcloudio/uni-mp-qq";
// Create cached event channel
const channel1 = initEventChannel({
dataReady: (data) => {
console.log('Data is ready:', data);
}
}, true); // cache = true (default)
// Create non-cached event channel
const channel2 = initEventChannel({
tempEvent: (info) => {
console.log('Temporary event:', info);
}
}, false); // cache = false
// Retrieve cached channel by ID
const retrievedChannel = getEventChannel(channel1.id);
console.log('Retrieved channel:', retrievedChannel === channel1); // true
// Retrieve next available cached channel (FIFO)
const nextChannel = getEventChannel(); // Returns first available cached channel
// Note: getEventChannel removes the channel from cache after retrieval
const sameChannel = getEventChannel(channel1.id); // Returns undefined (already consumed)Event channels integrate seamlessly with page navigation for communication between pages.
/**
* Navigation with event channel integration
* Automatically handled by uni.navigateTo when events are provided
*/
interface NavigationWithEvents {
/** Event channel is created automatically and passed in result */
eventChannel: EventChannel;
}Usage Examples:
// Page A - Navigate to Page B with event communication
const navigationResult = await uni.navigateTo({
url: '/pages/detail/detail?id=123',
events: {
// Events that Page B can emit back to Page A
dataUpdate: (updatedData) => {
console.log('Received updated data from detail page:', updatedData);
this.updateLocalData(updatedData);
},
actionPerformed: (actionType, result) => {
console.log(`Detail page performed ${actionType}:`, result);
this.handleDetailAction(actionType, result);
},
pageReady: () => {
console.log('Detail page is ready');
// Send initial data to detail page
navigationResult.eventChannel.emit('initialData', {
userData: this.userData,
preferences: this.preferences
});
}
}
});
// Send data to Page B
navigationResult.eventChannel.emit('configUpdate', {
theme: 'dark',
language: 'en-US'
});
// Page B - Receive and respond to events
export default {
onLoad(options) {
// Get event channel passed from Page A
const eventChannel = this.getOpenerEventChannel();
// Listen for events from Page A
eventChannel.on('initialData', (data) => {
console.log('Received initial data from opener:', data);
this.userData = data.userData;
this.preferences = data.preferences;
this.initializeWithData();
});
eventChannel.on('configUpdate', (config) => {
console.log('Config updated:', config);
this.applyConfiguration(config);
});
// Emit events back to Page A
eventChannel.emit('pageReady');
// Emit data updates
setTimeout(() => {
eventChannel.emit('dataUpdate', {
newData: 'Updated from detail page',
timestamp: Date.now()
});
}, 2000);
},
methods: {
handleUserAction(actionType) {
const eventChannel = this.getOpenerEventChannel();
// Process action
const result = this.processAction(actionType);
// Notify opener page
eventChannel.emit('actionPerformed', actionType, result);
}
}
};Event channels support automatic event caching when no listeners are present.
// Events emitted before listeners are registered get cached
const channel = initEventChannel();
// Emit event before any listeners are registered
channel.emit('earlyEvent', 'This will be cached');
// Register listener later - cached event will be replayed
channel.on('earlyEvent', (message) => {
console.log('Received cached event:', message); // "This will be cached"
});Advanced listener management with type-based behavior.
const channel = initEventChannel();
// Regular listeners persist until manually removed
channel.on('persistentEvent', () => {
console.log('This listener persists');
});
// One-time listeners are automatically removed after first execution
channel.once('oneTimeEvent', () => {
console.log('This runs only once');
});
// Emit events multiple times
channel.emit('persistentEvent'); // Listener runs
channel.emit('persistentEvent'); // Listener runs again
channel.emit('oneTimeEvent'); // Listener runs and is removed
channel.emit('oneTimeEvent'); // Nothing happens (listener removed)Event channels have a managed lifecycle tied to page navigation.
// Channel creation during navigation
uni.navigateTo({
url: '/pages/target/target',
events: {
// Initial events create the channel
ready: () => console.log('Target ready')
}
}).then(result => {
// Channel is available in navigation result
const channel = result.eventChannel;
// Channel remains active during page lifetime
channel.emit('initData', initialData);
});
// In target page
export default {
data() {
return {
eventChannel: null
};
},
onLoad() {
// Retrieve channel created during navigation
this.eventChannel = this.getOpenerEventChannel();
// Channel is automatically cleaned up when page is destroyed
},
onUnload() {
// Channel cleanup happens automatically
// No manual cleanup required
}
};Complex applications can use multiple event channels for different purposes.
// Create separate channels for different concerns
const dataChannel = initEventChannel({
dataUpdate: handleDataUpdate,
dataError: handleDataError
});
const uiChannel = initEventChannel({
themeChange: handleThemeChange,
layoutUpdate: handleLayoutUpdate
});
const analyticsChannel = initEventChannel({
userAction: trackUserAction,
pageView: trackPageView
});
// Use channels for specific purposes
dataChannel.emit('dataUpdate', newData);
uiChannel.emit('themeChange', 'dark');
analyticsChannel.emit('userAction', 'button_click');// Requester side
const channel = initEventChannel();
channel.once('response', (data) => {
console.log('Received response:', data);
});
channel.emit('request', { type: 'getData', params: { id: 123 } });
// Responder side
channel.on('request', (requestData) => {
const { type, params } = requestData;
if (type === 'getData') {
const data = fetchData(params.id);
channel.emit('response', data);
}
});// Publisher
const channel = initEventChannel();
setInterval(() => {
channel.emit('statusUpdate', {
status: 'active',
timestamp: Date.now(),
data: getCurrentStatus()
});
}, 5000);
// Subscribers
channel.on('statusUpdate', (update) => {
console.log('Subscriber 1 received:', update);
updateUI(update);
});
channel.on('statusUpdate', (update) => {
console.log('Subscriber 2 received:', update);
logStatusChange(update);
});// State manager
const stateChannel = initEventChannel();
let globalState = { user: null, theme: 'light' };
stateChannel.on('stateChange', (newState) => {
globalState = { ...globalState, ...newState };
stateChannel.emit('stateUpdated', globalState);
});
// State consumers
stateChannel.on('stateUpdated', (state) => {
console.log('State updated:', state);
updateComponentState(state);
});
// State updaters
stateChannel.emit('stateChange', { theme: 'dark' });
stateChannel.emit('stateChange', { user: { id: 123, name: 'John' } });navigateTo with eventsgetOpenerEventChannel()