如何在按钮onClick触发时从Stripe cardElement提取账单详情
问题根源与解决方案
核心说明
你无法从cardElement实例中提取外部自定义邮编输入框的内容:
- Stripe的
CardElement默认仅收集卡号、有效期、CVC三类卡面信息,外部独立输入的邮编值不会被存储到cardElement实例中,没有对应的API可以提取该值。 - 你当前报错的本质原因是事件绑定错误:按钮的
onClick事件中ev.target指向按钮本身,自然拿不到同页面其他位置的邮编输入框值。
方案1:使用表单submit事件(官方推荐规范写法)
这是Stripe官方示例采用的标准写法,改动成本最低:
- 将邮编输入框、CardElement、提交按钮全部包裹在
<form>标签内,给邮编输入框加上name="zip"属性,给按钮加上type="submit"属性 - 将
handleSubmit绑定到form的onSubmit事件上,而不是按钮的onClick事件 - 函数开头加
ev.preventDefault()阻止表单默认跳转行为,此时ev.target指向整个form元素,可以直接通过name属性获取输入值
修正后的代码参考:
// 表单结构 <form onSubmit={handleSubmit}> {/* 邮编输入框必须加name="zip" */} <input type="text" name="zip" placeholder="请输入账单邮编" required /> <CardElement /* 保留你原有CardElement配置 */ /> <button className='stripe-button' type="submit" disabled={isProcessing || !stripe} > Start Subscription </button> </form>
// handleSubmit逻辑 const handleSubmit = async (ev) => { ev.preventDefault(); // 必须加,阻止表单默认刷新跳转 setIsProcessing(true); const cardElement = elements.getElement('card'); try { cardElement.update({ disabled: true }); const apiBaseUrl = config.url.API_URL; const id = userData.user ? userData.user._id : null; // 此时ev.target为form实例,可正常获取zip输入值 const billingDetails = { address: { postal_code: ev.target.zip.value.trim() } }; const paymentMethodReq = await stripe.createPaymentMethod({ type: 'card', card: cardElement, billing_details: billingDetails }); if (paymentMethodReq.error) { // 错误场景记得恢复按钮和输入框状态 cardElement.update({ disabled: false }); setIsProcessing(false); // 你的错误提示逻辑 return; } const paymentObject = { id, paymentMethod: paymentMethodReq.paymentMethod.id }; await Axios.post(`${apiBaseUrl}/stripe/payment_subscriptions`, paymentObject); setIsProcessing(false); // 支付成功后的跳转/提示逻辑 } catch (error) { cardElement.update({ disabled: false }); setIsProcessing(false); // 你的异常处理逻辑 } };
方案2:受控组件存储邮编值(无需改动表单结构)
如果你不想调整现有DOM结构,可以通过React受控组件的方式单独管理邮编值,完全不需要依赖事件对象获取输入:
- 单独声明state存储邮编输入值,将邮编输入框改为受控组件
- 提交逻辑中直接读取state中的邮编值即可
代码参考:
// 组件内声明邮编state const [zipCode, setZipCode] = useState(''); // 邮编输入框绑定state <input type="text" value={zipCode} onChange={(e) => setZipCode(e.target.value.trim())} placeholder="请输入账单邮编" />
// handleSubmit中直接使用state值,无需从ev取 const billingDetails = { address: { postal_code: zipCode } };
额外说明
如果你在初始化CardElement时配置了hidePostalCode: false,即开启了Stripe组件内置的邮编收集功能,那么调用createPaymentMethod时Stripe会自动将收集到的邮编带入billing_details,你不需要额外传入postal_code参数。但这种方式对邮编输入框的样式、校验自定义程度很低,更推荐上述两种自行收集邮编的方案。
内容的提问来源于stack exchange,提问作者Canovice
相关产品推荐
相关产品推荐

