面试题答案
一键面试设计思路
- 事件中心模式:利用一个全局的事件中心来管理所有组件间的通信。每个组件可以向事件中心订阅或发布事件,避免组件间直接的强耦合。
- 事件代理:在DOM树上选择一个合适的祖先元素作为代理节点,将事件委托到该节点上处理,减少事件绑定数量,提升性能。
- 性能优化:
- 避免重复绑定事件,确保每个事件处理函数只被绑定一次。
- 合理使用节流(throttle)和防抖(debounce)技术,对于高频触发的事件进行优化。
- 内存管理:
- 在组件销毁时,及时取消订阅的事件,防止内存泄漏。
- 确保事件处理函数中的引用正确释放。
- 可维护性:
- 采用模块化的方式组织代码,将事件相关的逻辑封装在独立的模块中。
- 使用清晰的命名规范,便于理解和维护。
关键代码片段
- 事件中心模块(eventBus.js)
class EventBus {
constructor() {
this.events = {};
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
emit(eventName, ...args) {
const callbacks = this.events[eventName];
if (callbacks) {
callbacks.forEach(callback => callback(...args));
}
}
off(eventName, callback) {
const callbacks = this.events[eventName];
if (callbacks) {
this.events[eventName] = callbacks.filter(cb => cb!== callback);
}
}
}
export const eventBus = new EventBus();
- 组件中使用事件中心进行通信
import { eventBus } from './eventBus.js';
// 组件A发布事件
function ComponentA() {
const sendData = () => {
const data = { message: 'Hello from ComponentA' };
eventBus.emit('customEvent', data);
};
return <button onClick={sendData}>Send Event</button>;
}
// 组件B订阅事件
function ComponentB() {
const handleEvent = (data) => {
console.log('Received data in ComponentB:', data);
};
useEffect(() => {
eventBus.on('customEvent', handleEvent);
return () => {
eventBus.off('customEvent', handleEvent);
};
}, []);
return <div>ComponentB is listening for events</div>;
}
- 事件代理示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Event Delegation</title>
</head>
<body>
<ul id="parent">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
const parent = document.getElementById('parent');
parent.addEventListener('click', function (event) {
if (event.target.tagName === 'LI') {
console.log('Clicked on:', event.target.textContent);
}
});
</script>
</body>
</html>
在上述代码中,eventBus.js
实现了一个简单的事件中心,组件通过 eventBus
进行事件的发布和订阅。同时给出了使用 useEffect
钩子在组件挂载和卸载时处理事件订阅和取消订阅,确保内存管理。事件代理的示例展示了如何在DOM层面利用事件冒泡机制减少事件绑定数量。