一、技术背景与设计目标
前端支付组件开发面临的核心挑战:
- 多场景复用:需适配PC端收银台、移动端H5、小程序等不同载体
- 状态复杂:包含支付中、成功、失败、退款等10+状态流转
- 安全合规:需处理敏感信息(如银行卡号脱敏)、防重复提交、XSS防护
- 性能要求:首次加载时间需控制在300ms内,支持高频操作(如快速切换支付方式)
二、组件架构设计
采用"原子化设计+状态管理分离"模式,核心结构如下:
bash
PaymentComponents/
├─ atoms/ # 基础原子组件
│ ├─ PayButton/ # 支付按钮(加载/禁用状态)
│ ├─ QrCode/ # 二维码展示(刷新/过期提示)
│ └─ InputMask/ # 带脱敏的输入框(卡号/手机号)
├─ molecules/ # 复合组件
│ ├─ PayMethodSelector/ # 支付方式选择器
│ └─ OrderSummary/ # 订单摘要(金额/商品)
├─ organisms/ # 业务组件
│ ├─ ScanPay/ # 扫码支付组件
│ └─ FormPay/ # 表单支付组件(如银行卡)
└─ hooks/ # 状态管理钩子
├─ usePaymentStatus/ # 支付状态管理
└─ useSecurity/ # 安全处理(脱敏/加密)
三、核心技术实现
1. 高复用性组件设计
基于TypeScript的Props定义:
typescript
// 支付按钮Props设计
interface PayButtonProps {
amount: number; // 支付金额(必传)
onSubmit: (params: SubmitParams) => Promise<void>; // 提交回调
disabled?: boolean; // 是否禁用
loading?: boolean; // 加载状态
theme?: 'primary' | 'secondary'; // 主题样式
// 安全相关配置
security?: {
preventDoubleClick?: boolean; // 防重复点击
timeout?: number; // 按钮冷却时间(ms)
};
}
// 实现防重复点击逻辑
const PayButton: React.FC<PayButtonProps> = ({
amount, onSubmit, disabled, loading, theme = 'primary',
security = { preventDoubleClick: true, timeout: 3000 }
}) => {
const [isProcessing, setIsProcessing] = useState(false);
const handleClick = async () => {
if (isProcessing || disabled) return;
if (security.preventDoubleClick) {
setIsProcessing(true);
try {
await onSubmit({ amount });
} finally {
setTimeout(() => setIsProcessing(false), security.timeout);
}
} else {
await onSubmit({ amount });
}
};
return (
<button
className={`pay-button pay-button--${theme} ${isProcessing || loading ? 'pay-button--loading' : ''}`}
onClick={handleClick}
disabled={isProcessing || disabled || loading}
>
{isProcessing || loading ? <LoadingSpinner /> : `支付 ${amount.toFixed(2)}元`}
</button>
);
};
2. 支付状态管理
自定义Hook封装状态逻辑:
typescript
// usePaymentStatus.ts
export function usePaymentStatus(initialStatus: PaymentStatus = 'idle') {
const [status, setStatus] = useState<PaymentStatus>(initialStatus);
const [error, setError] = useState<Error | null>(null);
const statusRef = useRef(status);
// 状态更新副作用
useEffect(() => {
statusRef.current = status;
// 状态变更日志(可接入监控)
console.log(`Payment status changed: ${status}`);
}, [status]);
// 状态转换方法
const transition = useCallback((newStatus: PaymentStatus, err?: Error) => {
// 状态流转校验(防止非法状态切换)
const validTransitions: Record<PaymentStatus, PaymentStatus[]> = {
idle: ['processing', 'cancelled'],
processing: ['success', 'failed', 'timeout'],
success: ['refunding', 'refunded'],
// 其他状态映射...
};
if (!validTransitions[statusRef.current].includes(newStatus)) {
throw new Error(`Invalid status transition: ${statusRef.current} → ${newStatus}`);
}
setStatus(newStatus);
if (err) setError(err);
else setError(null);
}, []);
return { status, error, transition };
}
3. 安全处理机制
敏感信息脱敏与加密:
typescript
// useSecurity.ts
export function useSecurity() {
// 卡号脱敏:保留前6后4位
const maskCardNumber = useCallback((cardNo: string): string => {
if (!cardNo) return '';
return cardNo.replace(/^(\d{6})\d*(\d{4})$/, '$1 **** **** $2');
}, []);
// 支付参数加密(基于公钥)
const encryptPaymentParams = useCallback((params: Record<string, any>, publicKey: string) => {
// 使用jsencrypt进行RSA加密
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
return {
...params,
// 敏感字段加密
cardNo: encryptor.encrypt(params.cardNo || ''),
cvv: encryptor.encrypt(params.cvv || '')
};
}, []);
return { maskCardNumber, encryptPaymentParams };
}
四、性能与体验优化
- 代码分割与懒加载:
typescript
// 路由级别懒加载
const ScanPayModule = React.lazy(() => import('./organisms/ScanPay'));
// 组件使用
<Suspense fallback={<LoadingSkeleton />}>
<ScanPayModule orderId={orderId} />
</Suspense>
- 骨架屏与过渡动画:减少加载等待感知
- 离线支持:PWA缓存静态资源,支持弱网环境下基础展示
五、总结
本方案通过原子化组件设计、TypeScript类型约束、自定义Hook状态管理,构建了高复用、高安全的React支付组件库。代码示例覆盖核心组件封装、状态流转控制、安全处理等关键环节,可直接应用于电商、零售、餐饮等多场景支付需求。组件设计遵循单一职责原则,兼顾性能优化与开发体验,支持日均100万+前端支付请求场景。
**附:官方支付接口文档