React使用dangerouslySetInnerHTML时HTML无法渲染的问题排查
React 17.0.1中dangerouslySetInnerHTML渲染长HTML无显示的问题解决
问题场景
我定义了一段包含支付表单和自动提交脚本的HTML字符串:
const helpContent ="<form name=\"punchout_form\" method=\"post\" action=\"https://openapi.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=nKG8mCXQlGKOHezlqu7nM9ZJWskZsYVzWyW4Rm0dS%2BT8A4iWs3A96gwaqcdCwINIYacXQbtErYAM7GNAaqWFTNdl33Xj%2BVbEPqew%2BXO2yoihRU8onV0Omt5eo01PRITGEbclLI5v6VmpBwzbrzMawu63dSXTRWJ2jRga5ZUr1cnvexYQj3NLWH5eQS7ZHXwLhbOFlVOyostdF%2FSd9YJTFNotz25K1eipLI4JdG3%2BtaLLBQsNDahET09KWkxKjALSrZGIT48KLOmKWDMXkXTJzHSxjvOFxYKtBmwRenkRxt1wTWX21LgLH3Bi8k4N1KFNuj4FxrzI%2FJGOa58%2BULO54Q%3D%3D&return_url=http%3A%2F%2Fdomain.com%2FCallBack%2Freturn_url.jsp¬ify_url=http%3A%2F%2Fdomain.com%2FCallBack%2Fnotify_url.jsp&version=1.0&app_id=2021000122621126&sign_type=RSA2×tamp=2023-03-07+02%3A00%3A53&alipay_sdk=alipay-sdk-java-4.35.65.ALL&format=json\"> <input type=\"hidden\" name=\"biz_content\" value=\"{"extendParams":"dd","outTradeNo":"dd","passbackParams":"ddd","productCode":"productCode","subject":"ddd","sysServiceProviderId":"ddd","totalAmount":"1"}\"> <input type=\"submit\" value=\"立即支付\" style=\"display:none\" > </form> <script>document.forms[0].submit();</script>";
在React 17.0.1中通过dangerouslySetInnerHTML渲染:
<div style={{paddingLeft: 15, textIndent: 2}} dangerouslySetInnerHTML={{__html:helpContent}}></div>
但页面完全没有显示,而渲染简单HTML(如const helpContent = "<span>测试文本</span>")时却正常。
原因分析
- 自动提交脚本触发页面跳转:HTML里的
<script>document.forms[0].submit();</script>会在渲染完成后立刻提交表单,页面直接跳转到支付宝支付网关,所以当前页面的表单还没来得及展示就跳转了,自然看不到任何UI。 - 表单无可见元素:就算脚本不执行,提交按钮设置了
display:none,表单里只有隐藏的输入框,没有任何可见内容,页面也不会有显示。
解决方案
方案1:调试时查看表单结构
如果只是想确认表单的正确性,修改HTML字符串:
- 删除自动提交的
<script>部分 - 去掉提交按钮的
style="display:none"
修改后的代码示例:
const helpContent = "<form name=\"punchout_form\" method=\"post\" action=\"https://openapi.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=nKG8mCXQlGKOHezlqu7nM9ZJWskZsYVzWyW4Rm0dS%2BT8A4iWs3A96gwaqcdCwINIYacXQbtErYAM7GNAaqWFTNdl33Xj%2BVbEPqew%2BXO2yoihRU8onV0Omt5eo01PRITGEbclLI5v6VmpBwzbrzMawu63dSXTRWJ2jRga5ZUr1cnvexYQj3NLWH5eQS7ZHXwLhbOFlVOyostdF%2FSd9YJTFNotz25K1eipLI4JdG3%2BtaLLBQsNDahET09KWkxKjALSrZGIT48KLOmKWDMXkXTJzHSxjvOFxYKtBmwRenkRxt1wTWX21LgLH3Bi8k4N1KFNuj4FxrzI%2FJGOa58%2BULO54Q%3D%3D&return_url=http%3A%2F%2Fdomain.com%2FCallBack%2Freturn_url.jsp¬ify_url=http%3A%2F%2Fdomain.com%2FCallBack%2Fnotify_url.jsp&version=1.0&app_id=2021000122621126&sign_type=RSA2×tamp=2023-03-07+02%3A00%3A53&alipay_sdk=alipay-sdk-java-4.35.65.ALL&format=json\"> <input type=\"hidden\" name=\"biz_content\" value=\"{"extendParams":"dd","outTradeNo":"dd","passbackParams":"ddd","productCode":"productCode","subject":"ddd","sysServiceProviderId":"ddd","totalAmount":"1"}\"> <input type=\"submit\" value=\"立即支付\"> </form>";
方案2:让用户手动触发支付
如果需要保留支付功能,但希望用户确认后再提交:
- 删除自动提交的
<script>代码 - 移除提交按钮的
display:none样式,让按钮可见,用户点击后再提交表单
方案3:自动提交并显示加载状态(推荐)
如果必须自动跳转支付,同时想让用户看到加载提示,建议用React的组件逻辑实现,避免使用dangerouslySetInnerHTML:
import { useEffect } from 'react'; function AlipayPayment() { useEffect(() => { // 创建表单元素 const form = document.createElement('form'); form.name = 'punchout_form'; form.method = 'post'; form.action = 'https://openapi.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=nKG8mCXQlGKOHezlqu7nM9ZJWskZsYVzWyW4Rm0dS%2BT8A4iWs3A96gwaqcdCwINIYacXQbtErYAM7GNAaqWFTNdl33Xj%2BVbEPqew%2BXO2yoihRU8onV0Omt5eo01PRITGEbclLI5v6VmpBwzbrzMawu63dSXTRWJ2jRga5ZUr1cnvexYQj3NLWH5eQS7ZHXwLhbOFlVOyostdF%2FSd9YJTFNotz25K1eipLI4JdG3%2BtaLLBQsNDahET09KWkxKjALSrZGIT48KLOmKWDMXkXTJzHSxjvOFxYKtBmwRenkRxt1wTWX21LgLH3Bi8k4N1KFNuj4FxrzI%2FJGOa58%2BULO54Q%3D%3D&return_url=http%3A%2F%2Fdomain.com%2FCallBack%2Freturn_url.jsp¬ify_url=http%3A%2F%2Fdomain.com%2FCallBack%2Fnotify_url.jsp&version=1.0&app_id=2021000122621126&sign_type=RSA2×tamp=2023-03-07+02%3A00%3A53&alipay_sdk=alipay-sdk-java-4.35.65.ALL&format=json'; // 创建biz_content隐藏输入框 const bizInput = document.createElement('input'); bizInput.type = 'hidden'; bizInput.name = 'biz_content'; bizInput.value = '{"extendParams":"dd","outTradeNo":"dd","passbackParams":"ddd","productCode":"productCode","subject":"ddd","sysServiceProviderId":"ddd","totalAmount":"1"}'; form.appendChild(bizInput); // 添加到页面并提交 document.body.appendChild(form); form.submit(); // 组件卸载时清理表单 return () => { if (document.body.contains(form)) { document.body.removeChild(form); } }; }, []); return <div style={{paddingLeft: 15, textIndent: 2}}>正在跳转至支付宝支付...</div>; } export default AlipayPayment;
这种方式更符合React的开发规范,还能给用户明确的加载反馈,避免页面看起来没有响应。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

