Now.js Framework Documentation
EventSystemManager - DOM Event System
EventSystemManager - DOM Event System
เอกสารสำหรับ EventSystemManager ซึ่งเป็นระบบจัดการ DOM Events แบบ High-Performance
📋 สารบัญ
- ภาพรวม
- การติดตั้งและนำเข้า
- การใช้งานพื้นฐาน
- Event Delegation
- Keyboard Events
- Window Events
- Performance Optimization
- Memory Management
- Priority System
- Configuration
- ตัวอย่างการใช้งาน
- API Reference
- Best Practices
ภาพรวม
EventSystemManager เป็นระบบจัดการ DOM Events ที่ออกแบบมาเพื่อประสิทธิภาพสูงสุด พร้อมคุณสมบัติขั้นสูงเหนือกว่า addEventListener ปกติ
คุณสมบัติหลัก
- ✅ Event Delegation: จัดการ events แบบ centralized
- ✅ Auto Cleanup: ลบ handlers อัตโนมัติเมื่อ element ถูกลบ
- ✅ Memory Management: ตรวจสอบและจัดการหน่วยความจำ
- ✅ Priority System: กำหนดลำดับการทำงานของ handlers
- ✅ UI Event Optimization: ใช้ requestAnimationFrame สำหรับ UI events
- ✅ Keyboard Event Enhancement: ข้อมูล keyboard event ที่ครบถ้วน
- ✅ Throttle/Debounce: จำกัดอัตราการทำงานของ events
- ✅ Component Integration: เชื่อมต่อกับ Now.js Components
- ✅ MutationObserver: ติดตาม DOM changes
- ✅ Performance Monitoring: วัดและติดตามประสิทธิภาพ
ความแตกต่างจาก EventManager
| คุณสมบัติ | EventSystemManager | EventManager |
|---|---|---|
| จุดประสงค์ | DOM Events | Application Events |
| API หลัก | addHandler(), removeHandler() |
on(), emit(), off() |
| Event Types | DOM events (click, submit, etc.) | Custom events |
| Target | DOM elements | Application logic |
| Event Delegation | ✅ รองรับ | ❌ ไม่รองรับ |
| Auto Cleanup | ✅ รองรับ | ⚠️ Manual |
| Memory Monitoring | ✅ รองรับ | ❌ ไม่รองรับ |
| UI Optimization | ✅ requestAnimationFrame | ❌ ไม่รองรับ |
เมื่อใดควรใช้ EventSystemManager
✅ ใช้ EventSystemManager เมื่อ:
- ต้องการจัดการ DOM Events (click, submit, input, etc.)
- ต้องการ Event Delegation
- ต้องการ Auto Cleanup เมื่อ element ถูกลบ
- ต้องการ Performance Optimization
- ต้องการ Memory Management อัตโนมัติ
- ต้องการ Priority-based event handling
❌ อย่าใช้ EventSystemManager เมื่อ:
- ต้องการ Custom Application Events (ใช้ EventManager)
- ต้องการ Pattern Matching (ใช้ EventManager)
- ต้องการ Middleware (ใช้ EventManager)
- ต้องการ Event Groups (ใช้ EventManager)
การติดตั้งและนำเข้า
EventSystemManager โหลดพร้อมกับ Now.js Framework และเริ่มต้นอัตโนมัติ:
// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.EventSystemManager); // EventSystemManager object
// เข้าถึงผ่าน Now.js
const eventSystem = Now.getManager('eventsystem');Dependencies
EventSystemManager ต้องการ dependencies เหล่านี้:
- ErrorManager - สำหรับจัดการข้อผิดพลาด
การเริ่มต้นใช้งาน
EventSystemManager เริ่มต้นอัตโนมัติเมื่อโหลด Now.js:
// Auto-initialized
EventSystemManager.init();
// หรือ init พร้อม custom config
EventSystemManager.init({
delegation: {
enabled: true,
maxDelegationDepth: 10
},
memoryManagement: {
maxHandlersPerElement: 100,
maxCacheSize: 1000
}
});การใช้งานพื้นฐาน
1. Add Event Handler
// พื้นฐาน
const element = document.querySelector('#my-button');
const handlerId = EventSystemManager.addHandler(element, 'click', (event) => {
console.log('Button clicked!', event);
});
// พร้อม options
const id = EventSystemManager.addHandler(element, 'click', (event) => {
console.log('Clicked:', event.target);
}, {
capture: false,
once: false,
passive: true,
priority: 10
});2. Remove Event Handler
// ลบโดยใช้ handler ID
EventSystemManager.removeHandler(handlerId);
// ลบทุก handlers ของ component
EventSystemManager.removeComponentHandlers('my-component-id');3. Window Events
// Window events จัดการอัตโนมัติ
EventSystemManager.addHandler(window, 'resize', (event) => {
console.log('Window resized');
});
EventSystemManager.addHandler(window, 'scroll', (event) => {
console.log('Window scrolled');
});4. Document Events
// Document events
EventSystemManager.addHandler(document, 'click', (event) => {
console.log('Document clicked');
});Event Delegation
Event Delegation ช่วยให้จัดการ events ของ child elements ได้จาก parent
Basic Delegation
// จับ click บน child elements ที่ตรงกับ selector
const container = document.querySelector('#container');
EventSystemManager.addHandler(container, 'click', (event) => {
console.log('Button clicked:', event.delegateTarget);
}, {
selector: '.item-button' // จะทำงานเฉพาะ .item-button ภายใน container
});Use Cases สำหรับ Delegation
1. Dynamic Lists
// List ที่มี items เพิ่ม-ลบได้
const list = document.querySelector('#todo-list');
// จัดการ click บน delete buttons
EventSystemManager.addHandler(list, 'click', (event) => {
const item = event.delegateTarget;
const itemId = item.dataset.id;
deleteItem(itemId);
}, {
selector: '.delete-button'
});
// จัดการ click บน checkbox
EventSystemManager.addHandler(list, 'click', (event) => {
const checkbox = event.delegateTarget;
toggleItemComplete(checkbox);
}, {
selector: '.item-checkbox'
});2. Tables
// จัดการ click บน table rows
const table = document.querySelector('#data-table');
EventSystemManager.addHandler(table, 'click', (event) => {
const row = event.delegateTarget;
const rowId = row.dataset.id;
showRowDetails(rowId);
}, {
selector: 'tbody tr'
});
// จัดการ click บน edit buttons
EventSystemManager.addHandler(table, 'click', (event) => {
const button = event.delegateTarget;
const rowId = button.closest('tr').dataset.id;
editRow(rowId);
}, {
selector: '.edit-button'
});3. Modal/Dialog
// จัดการ click บน backdrop เพื่อปิด modal
EventSystemManager.addHandler(document.body, 'click', (event) => {
if (event.delegateTarget.classList.contains('modal-backdrop')) {
closeModal();
}
}, {
selector: '.modal-backdrop'
});Keyboard Events
EventSystemManager มี keyboard event enhancement พิเศษ
Enhanced Keyboard Events
EventSystemManager.addHandler(input, 'keydown', (event) => {
const enhanced = event.originalEvent._enhanced;
console.log('Key:', enhanced.key);
console.log('Code:', enhanced.code);
// Helper properties
if (enhanced.isEnter) {
console.log('Enter pressed');
}
if (enhanced.isShiftEnter) {
console.log('Shift+Enter pressed');
}
if (enhanced.isCtrlEnter) {
console.log('Ctrl+Enter pressed');
}
if (enhanced.isTab) {
console.log('Tab pressed');
}
if (enhanced.isShiftTab) {
console.log('Shift+Tab pressed');
}
if (enhanced.isArrowKey) {
console.log('Arrow key pressed:', enhanced.key);
}
// Modifiers
if (enhanced.ctrlKey) console.log('Ctrl is held');
if (enhanced.altKey) console.log('Alt is held');
if (enhanced.shiftKey) console.log('Shift is held');
if (enhanced.metaKey) console.log('Meta/Cmd is held');
});Keyboard Shortcuts
// Submit form with Ctrl+Enter
EventSystemManager.addHandler(textarea, 'keydown', (event) => {
const enhanced = event.originalEvent._enhanced;
if (enhanced.isCtrlEnter) {
event.preventDefault();
submitForm();
}
});
// Tab navigation with Shift+Tab
EventSystemManager.addHandler(form, 'keydown', (event) => {
const enhanced = event.originalEvent._enhanced;
if (enhanced.isShiftTab) {
// Custom tab navigation
navigateToPreviousField();
}
});
// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
if (event.key === 'Escape') {
closeAllModals();
}
});Window Events
จัดการ window-level events เช่น resize, scroll, popstate
Supported Window Events
// Resize
EventSystemManager.addHandler(window, 'resize', (event) => {
console.log('Window resized');
handleResize();
});
// Scroll
EventSystemManager.addHandler(window, 'scroll', (event) => {
console.log('Window scrolled');
handleScroll();
});
// Popstate (history navigation)
EventSystemManager.addHandler(window, 'popstate', (event) => {
console.log('History state changed');
handlePopState(event);
});
// Hashchange
EventSystemManager.addHandler(window, 'hashchange', (event) => {
console.log('Hash changed');
handleHashChange();
});
// Load
EventSystemManager.addHandler(window, 'load', (event) => {
console.log('Window loaded');
initialize();
});
// Online/Offline
EventSystemManager.addHandler(window, 'online', (event) => {
console.log('Connection restored');
syncData();
});
EventSystemManager.addHandler(window, 'offline', (event) => {
console.log('Connection lost');
showOfflineMessage();
});Performance Optimization
EventSystemManager มีกลไกเพิ่มประสิทธิภาพหลายอย่าง
UI Event Optimization
UI events (resize, scroll, mousemove) ใช้ requestAnimationFrame:
// Optimized automatically
EventSystemManager.addHandler(window, 'scroll', (event) => {
// ทำงานใน requestAnimationFrame
updateScrollPosition();
});
EventSystemManager.addHandler(window, 'resize', (event) => {
// Batched ใน requestAnimationFrame
recalculateLayout();
});
EventSystemManager.addHandler(element, 'mousemove', (event) => {
// Queued และประมวลผลรวมกัน
updateMousePosition(event);
});Throttle และ Debounce
// Throttle - จำกัดอัตราการทำงาน
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
const now = Date.now();
if (now - lastTime < 100) return; // throttle 100ms
lastTime = now;
handleScroll();
});
// Debounce - รอให้หยุดแล้วค่อยทำงาน
let debounceTimer;
EventSystemManager.addHandler(window, 'resize', (event) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
handleResize();
}, 200); // debounce 200ms
});Event Filtering
EventSystemManager มี built-in event filtering:
// Configuration
EventSystemManager.config.filtering = {
enabled: true,
maxThrottleRate: 60, // events per second
debounceWait: 100,
highFrequencyEvents: new Set([
'mousemove',
'scroll',
'resize',
'touchmove',
'pointermove'
])
};Memory Management
EventSystemManager จัดการหน่วยความจำอัตโนมัติ
Auto Cleanup
// Handlers ถูกลบอัตโนมัติเมื่อ element ถูกลบจาก DOM
const element = document.createElement('div');
document.body.appendChild(element);
const id = EventSystemManager.addHandler(element, 'click', handler);
// ลบ element - handler ถูกลบอัตโนมัติ
element.remove();Manual Cleanup
// ลบ handler เฉพาะ
EventSystemManager.removeHandler(handlerId);
// ลบทุก handlers ของ component
EventSystemManager.removeComponentHandlers('component-id');
// Cleanup ทั้งหมด
EventSystemManager.cleanup();
// Destroy
EventSystemManager.destroy();Memory Monitoring
// ตรวจสอบ memory usage
const stats = EventSystemManager.gatherMemoryStats();
console.log('Handlers:', stats.handlerCount);
console.log('Cache size:', stats.cacheSize);
console.log('WeakMap size:', stats.weakMapSize);
// Memory stats
console.log(EventSystemManager.state.memoryStats);
// {
// handlerCount: 42,
// cacheSize: 15,
// weakMapSize: 8,
// lastGC: 1698765432100,
// peakMemoryUsage: 50,
// memoryWarnings: 0
// }Garbage Collection
// Manual GC trigger
EventSystemManager.performGC();
// Auto GC configuration
EventSystemManager.config.memoryManagement = {
checkInterval: 30000, // ตรวจสอบทุก 30 วินาที
maxHandlersPerElement: 100, // handlers สูงสุดต่อ element
maxCacheSize: 1000, // cache size สูงสุด
gcThreshold: 0.8, // trigger GC ที่ 80%
detailedTracking: true // เปิด detailed logging
};Priority System
กำหนดลำดับการทำงานของ handlers
Priority Values
// Priority สูง - ทำก่อน
EventSystemManager.addHandler(element, 'click', validationHandler, {
priority: 100
});
// Priority กลาง
EventSystemManager.addHandler(element, 'click', transformHandler, {
priority: 50
});
// Priority ต่ำ - ทำหลัง
EventSystemManager.addHandler(element, 'click', submitHandler, {
priority: 10
});
// Default priority (0) - ทำหลังสุด
EventSystemManager.addHandler(element, 'click', loggingHandler);Use Cases สำหรับ Priority
1. Form Validation Pipeline
// Validate ก่อน
EventSystemManager.addHandler(form, 'submit', (event) => {
if (!validateForm()) {
event.preventDefault();
event.stopImmediatePropagation();
}
}, {priority: 100});
// Transform data
EventSystemManager.addHandler(form, 'submit', (event) => {
transformFormData();
}, {priority: 50});
// Submit - ทำหลังสุด
EventSystemManager.addHandler(form, 'submit', (event) => {
submitFormData();
}, {priority: 10});2. Click Handlers
// Check permissions ก่อน
EventSystemManager.addHandler(button, 'click', (event) => {
if (!hasPermission()) {
event.preventDefault();
event.stopPropagation();
showPermissionError();
}
}, {priority: 100});
// Actual action
EventSystemManager.addHandler(button, 'click', (event) => {
performAction();
}, {priority: 50});Configuration
Configuration Options
const config = {
cleanupInterval: 600000, // Cleanup interval (ms)
maxMemoryUsage: 52428800, // Max memory (50MB)
delegation: {
enabled: true,
matchingStrategy: 'closestFirst',
maxDelegationDepth: 10,
optimizeSelectors: true,
rootElement: document.body
},
memoryManagement: {
checkInterval: 30000,
maxHandlersPerElement: 100,
maxCacheSize: 1000,
gcThreshold: 0.8,
detailedTracking: true
},
filtering: {
enabled: true,
maxThrottleRate: 60,
debounceWait: 100,
highFrequencyEvents: null // Set หรือ null
}
};Update Configuration
// Update individual settings
EventSystemManager.config.memoryManagement.maxHandlersPerElement = 200;
EventSystemManager.config.delegation.maxDelegationDepth = 15;
// Update filtering
EventSystemManager.config.filtering.enabled = true;
EventSystemManager.config.filtering.maxThrottleRate = 30;ตัวอย่างการใช้งาน
1. Form Handling
const form = document.querySelector('#registration-form');
// Submit handler
EventSystemManager.addHandler(form, 'submit', (event) => {
event.preventDefault();
// Validate
if (!validateForm(form)) {
showErrors();
return;
}
// Submit
const formData = new FormData(form);
submitRegistration(formData);
}, {
priority: 50
});
// Real-time validation
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
EventSystemManager.addHandler(input, 'blur', (event) => {
validateField(event.target);
});
EventSystemManager.addHandler(input, 'input', (event) => {
clearFieldError(event.target);
});
});2. Dynamic List with Delegation
const todoList = document.querySelector('#todo-list');
// Add item
EventSystemManager.addHandler(todoList, 'click', (event) => {
const item = event.delegateTarget;
const itemId = item.dataset.id;
addTodoItem(itemId);
}, {
selector: '.add-button'
});
// Toggle complete
EventSystemManager.addHandler(todoList, 'click', (event) => {
const checkbox = event.delegateTarget;
const itemId = checkbox.closest('.todo-item').dataset.id;
toggleComplete(itemId, checkbox.checked);
}, {
selector: '.todo-checkbox'
});
// Delete item
EventSystemManager.addHandler(todoList, 'click', (event) => {
const button = event.delegateTarget;
const itemId = button.closest('.todo-item').dataset.id;
deleteItem(itemId);
}, {
selector: '.delete-button'
});
// Edit item
EventSystemManager.addHandler(todoList, 'click', (event) => {
const button = event.delegateTarget;
const itemId = button.closest('.todo-item').dataset.id;
editItem(itemId);
}, {
selector: '.edit-button'
});3. Keyboard Navigation
const searchBox = document.querySelector('#search-box');
const results = document.querySelector('#search-results');
EventSystemManager.addHandler(searchBox, 'keydown', (event) => {
const enhanced = event.originalEvent._enhanced;
if (enhanced.isArrowKey) {
event.preventDefault();
if (enhanced.key === 'ArrowDown') {
focusNextResult();
} else if (enhanced.key === 'ArrowUp') {
focusPreviousResult();
}
}
if (enhanced.isEnter) {
const focused = results.querySelector('.focused');
if (focused) {
selectResult(focused);
}
}
if (event.key === 'Escape') {
closeResults();
}
});4. Scroll Handling
// Infinite scroll
let isLoading = false;
EventSystemManager.addHandler(window, 'scroll', (event) => {
if (isLoading) return;
const scrollPosition = window.scrollY + window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
if (scrollPosition >= documentHeight - 200) {
isLoading = true;
loadMoreContent().then(() => {
isLoading = false;
});
}
});
// Sticky header
const header = document.querySelector('#header');
EventSystemManager.addHandler(window, 'scroll', (event) => {
if (window.scrollY > 100) {
header.classList.add('sticky');
} else {
header.classList.remove('sticky');
}
});5. Drag and Drop
const draggable = document.querySelector('.draggable');
const dropzone = document.querySelector('.dropzone');
// Drag start
EventSystemManager.addHandler(draggable, 'dragstart', (event) => {
event.originalEvent.dataTransfer.effectAllowed = 'move';
event.originalEvent.dataTransfer.setData('text/html', event.target.innerHTML);
event.target.classList.add('dragging');
});
// Drag end
EventSystemManager.addHandler(draggable, 'dragend', (event) => {
event.target.classList.remove('dragging');
});
// Drag over
EventSystemManager.addHandler(dropzone, 'dragover', (event) => {
event.preventDefault();
event.originalEvent.dataTransfer.dropEffect = 'move';
dropzone.classList.add('drag-over');
});
// Drag leave
EventSystemManager.addHandler(dropzone, 'dragleave', (event) => {
dropzone.classList.remove('drag-over');
});
// Drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
event.preventDefault();
dropzone.classList.remove('drag-over');
const data = event.originalEvent.dataTransfer.getData('text/html');
handleDrop(data);
});6. Modal Management
// Open modal
function openModal(modalId) {
const modal = document.querySelector(`#${modalId}`);
modal.classList.add('active');
// Close on backdrop click
const backdropId = EventSystemManager.addHandler(modal, 'click', (event) => {
if (event.target === modal) {
closeModal(modalId);
EventSystemManager.removeHandler(backdropId);
}
});
// Close on Escape
const escapeId = EventSystemManager.addHandler(document, 'keydown', (event) => {
if (event.key === 'Escape') {
closeModal(modalId);
EventSystemManager.removeHandler(escapeId);
}
});
}
function closeModal(modalId) {
const modal = document.querySelector(`#${modalId}`);
modal.classList.remove('active');
}7. Context Menu
const contextMenu = document.querySelector('#context-menu');
// Show context menu
EventSystemManager.addHandler(document, 'contextmenu', (event) => {
if (!event.target.closest('.has-context-menu')) return;
event.preventDefault();
contextMenu.style.left = event.originalEvent.pageX + 'px';
contextMenu.style.top = event.originalEvent.pageY + 'px';
contextMenu.classList.add('active');
});
// Hide context menu
EventSystemManager.addHandler(document, 'click', (event) => {
if (!event.target.closest('#context-menu')) {
contextMenu.classList.remove('active');
}
});
// Context menu actions
EventSystemManager.addHandler(contextMenu, 'click', (event) => {
const action = event.delegateTarget.dataset.action;
handleContextMenuAction(action);
contextMenu.classList.remove('active');
}, {
selector: '[data-action]'
});8. Table Sorting
const table = document.querySelector('#data-table');
EventSystemManager.addHandler(table, 'click', (event) => {
const th = event.delegateTarget;
const columnIndex = Array.from(th.parentElement.children).indexOf(th);
const currentSort = th.dataset.sort || 'none';
// Toggle sort direction
let newSort;
if (currentSort === 'none') newSort = 'asc';
else if (currentSort === 'asc') newSort = 'desc';
else newSort = 'none';
// Update UI
table.querySelectorAll('th').forEach(header => {
header.dataset.sort = 'none';
});
th.dataset.sort = newSort;
// Sort table
sortTable(table, columnIndex, newSort);
}, {
selector: 'th[data-sortable]'
});9. File Upload with Drag and Drop
const dropzone = document.querySelector('#file-dropzone');
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
EventSystemManager.addHandler(dropzone, eventName, (event) => {
event.preventDefault();
event.stopPropagation();
});
});
// Highlight dropzone
['dragenter', 'dragover'].forEach(eventName => {
EventSystemManager.addHandler(dropzone, eventName, (event) => {
dropzone.classList.add('highlight');
});
});
['dragleave', 'drop'].forEach(eventName => {
EventSystemManager.addHandler(dropzone, eventName, (event) => {
dropzone.classList.remove('highlight');
});
});
// Handle drop
EventSystemManager.addHandler(dropzone, 'drop', (event) => {
const files = event.originalEvent.dataTransfer.files;
handleFiles(files);
});
// Click to upload
EventSystemManager.addHandler(dropzone, 'click', (event) => {
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.onchange = (e) => handleFiles(e.target.files);
input.click();
});10. Responsive Navigation
const nav = document.querySelector('#main-nav');
const toggle = document.querySelector('#nav-toggle');
// Toggle mobile menu
EventSystemManager.addHandler(toggle, 'click', (event) => {
nav.classList.toggle('active');
});
// Close on outside click
EventSystemManager.addHandler(document, 'click', (event) => {
if (!event.target.closest('#main-nav') &&
!event.target.closest('#nav-toggle')) {
nav.classList.remove('active');
}
});
// Close on Escape
EventSystemManager.addHandler(document, 'keydown', (event) => {
if (event.key === 'Escape') {
nav.classList.remove('active');
}
});
// Handle resize
EventSystemManager.addHandler(window, 'resize', (event) => {
if (window.innerWidth > 768) {
nav.classList.remove('active');
}
});API Reference
Configuration
{
cleanupInterval: number, // Cleanup interval (ms)
maxMemoryUsage: number, // Max memory usage (bytes)
delegation: {
enabled: boolean, // Enable delegation
matchingStrategy: string, // 'closestFirst'
maxDelegationDepth: number, // Max depth
optimizeSelectors: boolean, // Optimize selectors
rootElement: HTMLElement // Root element
},
memoryManagement: {
checkInterval: number, // Check interval (ms)
maxHandlersPerElement: number, // Max handlers per element
maxCacheSize: number, // Max cache size
gcThreshold: number, // GC threshold (0-1)
detailedTracking: boolean // Detailed tracking
},
filtering: {
enabled: boolean, // Enable filtering
maxThrottleRate: number, // Max events per second
debounceWait: number, // Debounce wait (ms)
highFrequencyEvents: Set // High frequency events
}
}Methods
Core Methods
// Initialize
init(): EventSystemManager
// Add handler
addHandler(
element: Element|Window|Document,
type: string,
handler: function,
options?: {
capture?: boolean,
once?: boolean,
passive?: boolean,
priority?: number,
componentId?: string,
selector?: string
}
): number
// Remove handler
removeHandler(id: number): boolean
// Remove component handlers
removeComponentHandlers(componentId: string): voidCleanup Methods
// Manual cleanup
cleanup(): void
// Remove element handlers
removeElementHandlers(element: Element): void
// Destroy
destroy(): voidMemory Methods
// Gather memory stats
gatherMemoryStats(): object
// Check memory usage
checkMemoryUsage(): void
// Perform GC
performGC(): voidEvent Object
{
type: string, // Event type
key: string, // Key (keyboard events)
shiftKey: boolean, // Shift key pressed
ctrlKey: boolean, // Ctrl key pressed
altKey: boolean, // Alt key pressed
metaKey: boolean, // Meta key pressed
target: Element, // Event target
currentTarget: Element, // Current target
delegateTarget: Element, // Delegate target
timestamp: number, // Timestamp
originalEvent: Event, // Original DOM event
preventDefault(): void,
stopPropagation(): void,
stopImmediatePropagation(): void,
matches(selector: string): boolean
}Handler Options
{
capture: boolean, // Capture phase
once: boolean, // Execute once
passive: boolean, // Passive listener
priority: number, // Priority (higher = first)
componentId: string, // Component ID
selector: string // Delegation selector
}Best Practices
1. ✅ ใช้ Event Delegation
// ❌ Bad: handler แยกต่าง element
items.forEach(item => {
EventSystemManager.addHandler(item, 'click', handler);
});
// ✅ Good: ใช้ delegation
EventSystemManager.addHandler(container, 'click', handler, {
selector: '.item'
});2. ✅ Cleanup เมื่อ Destroy Component
// ✅ Good: เก็บ handler IDs
const MyComponent = {
handlerIds: [],
init() {
const id1 = EventSystemManager.addHandler(this.element, 'click', handler);
const id2 = EventSystemManager.addHandler(this.button, 'submit', handler);
this.handlerIds.push(id1, id2);
},
destroy() {
this.handlerIds.forEach(id => {
EventSystemManager.removeHandler(id);
});
}
};3. ✅ ใช้ Component ID
// ✅ Good: ใช้ componentId สำหรับ cleanup ง่าย
const componentId = 'my-component-123';
EventSystemManager.addHandler(element, 'click', handler, {
componentId
});
// Cleanup ทั้ง component พร้อมกัน
EventSystemManager.removeComponentHandlers(componentId);4. ✅ ใช้ Priority อย่างเหมาะสม
// ✅ Good: validation ก่อน submit
EventSystemManager.addHandler(form, 'submit', validateHandler, {
priority: 100
});
EventSystemManager.addHandler(form, 'submit', submitHandler, {
priority: 10
});5. ✅ ใช้ Passive สำหรับ Scroll/Touch
// ✅ Good: passive สำหรับ better performance
EventSystemManager.addHandler(element, 'touchstart', handler, {
passive: true
});
EventSystemManager.addHandler(window, 'scroll', handler, {
passive: true
});6. ✅ Throttle/Debounce UI Events
// ✅ Good: throttle scroll event
let lastTime = 0;
EventSystemManager.addHandler(window, 'scroll', (event) => {
const now = Date.now();
if (now - lastTime < 100) return;
lastTime = now;
handleScroll();
});7. ✅ ใช้ Once สำหรับ One-time Events
// ✅ Good: once สำหรับ event ที่ทำครั้งเดียว
EventSystemManager.addHandler(button, 'click', handler, {
once: true
});8. ✅ จัดการ Memory อย่างระมัดระวัง
// ✅ Good: ตรวจสอบ memory usage
setInterval(() => {
const stats = EventSystemManager.gatherMemoryStats();
if (stats.handlerCount > 500) {
console.warn('Too many handlers:', stats.handlerCount);
}
}, 60000);9. ✅ ใช้ stopPropagation อย่างระวัง
// ⚠️ Careful: stopPropagation อาจป้องกัน handlers อื่น
EventSystemManager.addHandler(button, 'click', (event) => {
// ใช้เฉพาะเมื่อจำเป็น
event.stopPropagation();
});10. ✅ Test บน Multiple Devices
// ✅ Good: รองรับทั้ง mouse และ touch
EventSystemManager.addHandler(element, 'click', handleClick);
EventSystemManager.addHandler(element, 'touchend', handleClick);สรุป
เมื่อใดควรใช้ EventSystemManager
| Use Case | ใช้ EventSystemManager? | หมายเหตุ |
|---|---|---|
| จัดการ DOM Events | ✅ ใช่ | click, submit, input, etc. |
| Event Delegation | ✅ ใช่ | Dynamic content |
| Auto Cleanup | ✅ ใช่ | Memory management |
| Performance Optimization | ✅ ใช่ | UI events |
| Keyboard Handling | ✅ ใช่ | Enhanced keyboard events |
| Custom Application Events | ❌ ไม่ | ใช้ EventManager |
| Pattern Matching | ❌ ไม่ | ใช้ EventManager |
| Middleware | ❌ ไม่ | ใช้ EventManager |
คุณสมบัติหลัก
| คุณสมบัติ | รองรับ | หมายเหตุ |
|---|---|---|
| Event Delegation | ✅ | Selector-based |
| Auto Cleanup | ✅ | MutationObserver |
| Memory Management | ✅ | Auto GC |
| Priority System | ✅ | Ordered execution |
| UI Optimization | ✅ | requestAnimationFrame |
| Keyboard Enhancement | ✅ | Helper properties |
| Throttle/Debounce | ✅ | Built-in filtering |
| Component Integration | ✅ | Component IDs |