React 事件处理完整指南
1. 基础事件处理
1.1 事件绑定方式
// 类组件中的事件处理
class ButtonComponent extends React.Component {
// 方法一:类字段语法(推荐)
handleClick = (e) => {
console.log('Button clicked', e);
}
// 方法二:构造函数中绑定
constructor(props) {
super(props);
this.handleClick2 = this.handleClick2.bind(this);
}
handleClick2() {
console.log('Button clicked 2');
}
render() {
return (
<div>
{/* 方法一:使用类字段定义的方法 */}
<button onClick={this.handleClick}>Click Me</button>
{/* 方法二:构造函数中绑定的方法 */}
<button onClick={this.handleClick2}>Click Me 2</button>
{/* 方法三:内联箭头函数(不推荐,每次渲染都会创建新函数) */}
<button onClick={(e) => this.handleClick3(e)}>Click Me 3</button>
</div>
);
}
}
// 函数组件中的事件处理
function ButtonFunction() {
const handleClick = (e) => {
console.log('Button clicked', e);
};
return <button onClick={handleClick}>Click Me</button>;
}
1.2 事件对象的使用
function EventObject() {
const handleClick = (e) => {
// 阻止默认行为
e.preventDefault();
// 阻止事件冒泡
e.stopPropagation();
// 获取事件目标
console.log(e.target);
// 获取原生事件对象
console.log(e.nativeEvent);
// 获取事件类型
console.log(e.type);
};
return (
<a href="https://example.com" onClick={handleClick}>
Click Me
</a>
);
}
2. 常见事件类型
2.1 鼠标事件
function MouseEvents() {
const handleMouseEvents = {
onClick: (e) => console.log('Clicked'),
onDoubleClick: (e) => console.log('Double clicked'),
onMouseEnter: (e) => console.log('Mouse entered'),
onMouseLeave: (e) => console.log('Mouse left'),
onMouseMove: (e) => console.log('Mouse moved', e.clientX, e.clientY),
onMouseDown: (e) => console.log('Mouse down'),
onMouseUp: (e) => console.log('Mouse up')
};
return (
<div
style={{ width: 200, height: 200, background: '#f0f0f0' }}
{...handleMouseEvents}
>
Mouse Events Demo
</div>
);
}
2.2 键盘事件
function KeyboardEvents() {
const handleKeyDown = (e) => {
console.log('Key pressed:', e.key);
console.log('Key code:', e.keyCode);
console.log('Ctrl key:', e.ctrlKey);
console.log('Alt key:', e.altKey);
console.log('Shift key:', e.shiftKey);
};
const handleKeyUp = (e) => {
console.log('Key released:', e.key);
};
return (
<input
type="text"
onKeyDown={handleKeyDown}
onKeyUp={handleKeyUp}
placeholder="Type something..."
/>
);
}
2.3 表单事件
function FormEvents() {
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted');
};
const handleChange = (e) => {
console.log('Input value:', e.target.value);
};
const handleFocus = () => {
console.log('Input focused');
};
const handleBlur = () => {
console.log('Input lost focus');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</form>
);
}
3. 事件处理进阶
3.1 事件委托
function EventDelegation() {
const handleClick = (e) => {
// 检查事件目标
if (e.target.tagName === 'LI') {
console.log('Clicked item:', e.target.textContent);
}
};
return (
<ul onClick={handleClick}>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
);
}
3.2 自定义事件处理
function CustomEventComponent() {
useEffect(() => {
// 创建自定义事件
const customEvent = new CustomEvent('myCustomEvent', {
detail: { message: 'Hello from custom event' }
});
// 添加事件监听器
const handleCustomEvent = (e) => {
console.log(e.detail.message);
};
document.addEventListener('myCustomEvent', handleCustomEvent);
// 触发自定义事件
document.dispatchEvent(customEvent);
// 清理
return () => {
document.removeEventListener('myCustomEvent', handleCustomEvent);
};
}, []);
return <div>Custom Event Demo</div>;
}
3.3 事件节流和防抖
function ThrottleAndDebounce() {
// 防抖
const debounce = (fn, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
};
// 节流
const throttle = (fn, delay) => {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= delay) {
fn(...args);
lastCall = now;
}
};
};
// 使用防抖的事件处理器
const handleChangeDebounced = debounce((e) => {
console.log('Debounced value:', e.target.value);
}, 500);
// 使用节流的事件处理器
const handleMoveThrottled = throttle((e) => {
console.log('Throttled position:', e.clientX, e.clientY);
}, 100);
return (
<div>
<input
type="text"
onChange={handleChangeDebounced}
placeholder="Debounced input"
/>
<div
onMouseMove={handleMoveThrottled}
style={{ height: 200, background: '#f0f0f0' }}
>
Move mouse here
</div>
</div>
);
}
4. 合成事件
4.1 事件池
function EventPoolExample() {
const handleClick = (e) => {
// React 17之前需要使用 e.persist()
// e.persist();
setTimeout(() => {
console.log(e.type); // 在 React 17+ 中可以正常工作
}, 0);
};
return <button onClick={handleClick}>Click Me</button>;
}
4.2 跨浏览器兼容性
function CrossBrowserEvent() {
const handleWheel = (e) => {
// React 统一了滚轮事件
console.log('Delta Y:', e.deltaY);
};
return (
<div onWheel={handleWheel} style={{ height: 200, background: '#f0f0f0' }}>
Scroll here
</div>
);
}
5. 最佳实践
5.1 性能优化
function OptimizedEventHandling() {
// 使用 useCallback 缓存事件处理函数
const handleClick = useCallback((e) => {
console.log('Clicked');
}, []);
// 使用 useMemo 缓存计算结果
const memoizedValue = useMemo(() => {
return expensiveCalculation();
}, []);
return (
<button onClick={handleClick}>
Click Me ({memoizedValue})
</button>
);
}
5.2 TypeScript 集成
interface EventProps {
onCustomClick: (value: string) => void;
}
function TypedEventComponent({ onCustomClick }: EventProps) {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
onCustomClick(e.currentTarget.value);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
return (
<div>
<button onClick={handleClick} value="button-value">
Click Me
</button>
<input onChange={handleChange} />
</div>
);
}
6. 总结
事件处理要点:
- 选择合适的事件绑定方式
- 正确处理事件对象
- 注意性能优化
- 适当使用事件委托
- 处理好事件清理工作
最佳实践:
- 使用类字段语法或 hooks 定义事件处理器
- 避免在 JSX 中使用内联函数
- 合理使用防抖和节流
- 使用 TypeScript 增加类型安全
- 注意内存泄漏问题