事件处理规范
组件开发规范和事件处理规范是前端工程化的重要组成部分,合理的规范能够提升代码的可维护性和团队协作效率。下面从组件开发、事件处理两个方面展开详细说明。
组件开发规范
组件命名规范
组件命名采用大驼峰式(PascalCase),与文件名保持一致。多单词组合要避免缩写,保持语义完整。
// Good
UserProfileCard.jsx
OrderStatusBadge.jsx
// Bad
userProfile.jsx // 不符合大驼峰
usrPrfCard.jsx // 不推荐缩写
目录结构
组件相关文件统一放在components
目录下,复杂组件建立独立文件夹:
src/
components/
Button/
index.jsx
style.module.css
Button.test.js
Form/
Input/
index.jsx
InputItem.jsx
Props 类型定义
必须使用 TypeScript 或 PropTypes 明确定义 props 类型:
interface ButtonProps {
size?: 'small' | 'medium' | 'large';
variant?: 'primary' | 'secondary';
disabled?: boolean;
onClick?: (event: React.MouseEvent) => void;
}
const Button: React.FC<ButtonProps> = ({
size = 'medium',
variant = 'primary',
...props
}) => {
/* ... */
}
样式管理
推荐 CSS Modules 或 styled-components:
// CSS Modules 示例
import styles from './Button.module.css';
const Button = () => (
<button className={`${styles.btn} ${styles.primary}`}>
Click
</button>
);
// styled-components 示例
const StyledButton = styled.button`
padding: ${props => props.size === 'large' ? '12px 24px' : '8px 16px'};
background: ${props => props.theme.primary};
`;
事件处理规范
命名约定
事件处理函数以handle
前缀开头,props 回调以on
前缀开头:
const handleClick = (e) => {
console.log('Button clicked', e.target);
};
<Button onClick={handleClick} />
// 组件内部暴露事件
function Modal({ onClose }) {
const handleClose = () => {
// 清理逻辑...
onClose?.();
};
}
事件对象处理
始终考虑事件代理和默认行为阻止:
// 列表项点击事件代理
function List({ items }) {
const handleClick = (e) => {
const itemId = e.target.dataset.id;
if (itemId) {
// 处理具体项点击
}
};
return (
<ul onClick={handleClick}>
{items.map(item => (
<li key={item.id} data-id={item.id}>{item.text}</li>
))}
</ul>
);
}
// 表单提交
const handleSubmit = (e) => {
e.preventDefault();
// 验证和处理数据
};
异步事件处理
需要处理加载状态和错误捕获:
function AsyncButton() {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
try {
setLoading(true);
await fetchData();
} catch (error) {
console.error('Fetch failed:', error);
} finally {
setLoading(false);
}
};
return <button onClick={handleClick} disabled={loading} />;
}
自定义事件
复杂组件需要定义详细的事件契约:
// 类型定义
type CalendarEvent = {
date: Date;
type: 'select' | 'hover';
nativeEvent: React.MouseEvent;
};
interface CalendarProps {
onDateChange?: (event: CalendarEvent) => void;
}
// 事件触发
const emitDateChange = (date: Date, type: CalendarEvent['type'], e: React.MouseEvent) => {
onDateChange?.({
date,
type,
nativeEvent: e
});
};
性能优化
事件节流与防抖
高频事件需要做性能优化:
import { throttle, debounce } from 'lodash-es';
// 滚动事件节流
const handleScroll = throttle((e) => {
console.log('Scrolling', e.target.scrollTop);
}, 200);
// 搜索框防抖
const handleSearch = debounce((keyword) => {
searchAPI(keyword);
}, 500);
事件监听清理
组件卸载时必须移除全局事件监听:
useEffect(() => {
const handleKeyDown = (e) => {
if (e.key === 'Escape') handleClose();
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, []);
可访问性规范
键盘事件
必须支持键盘操作:
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick();
}
}}
>
可点击元素
</div>
ARIA 属性
复杂组件需要添加 ARIA 属性:
<div
role="dialog"
aria-labelledby="dialog-title"
aria-modal="true"
>
<h2 id="dialog-title">提示</h2>
{/* 对话框内容 */}
</div>
测试规范
事件测试用例
使用 Testing Library 编写事件测试:
import { render, fireEvent } from '@testing-library/react';
test('should trigger onClick', () => {
const handleClick = jest.fn();
const { getByText } = render(<Button onClick={handleClick} />);
fireEvent.click(getByText('Submit'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
// 模拟键盘事件
test('should handle keyboard event', () => {
const { getByRole } = render(<SearchBox />);
const input = getByRole('searchbox');
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
// 验证搜索逻辑
});
文档规范
组件文档
使用 Storybook 或 JSDoc 记录组件事件:
/**
* 通用按钮组件
*
* @param {Object} props - 组件属性
* @param {'small'|'medium'|'large'} [props.size=medium] - 按钮尺寸
* @param {Function} props.onClick - 点击事件回调
*/
export function Button({ size = 'medium', onClick }) {
// ...
}
事件流程图
复杂交互建议绘制事件流程图:
用户点击 → 触发handleClick → 验证数据 → 调用onSubmit → 发起API请求
↑ ↓
错误反馈 ← 请求失败
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn