动态生成嵌入iframe的<script>标签函数无法调用问题求助
当你通过contentWindow.document.body.innerHTML = data将HTML内容插入iframe时,浏览器不会自动执行其中的<script>标签——这是浏览器的安全机制,避免innerHTML注入的脚本被意外执行。即使脚本标签存在于DOM中,也不会被解析执行,这就是为什么手动在控制台输入函数能运行,但点击按钮找不到函数的原因。另外你拼接的脚本里还有语法错误:var url = updateRecorderInfoServlet?RecorderID=' + RecorderID缺少开头的单引号和结尾的分号,会导致脚本本身就无法运行。
下面提供几种可行的解决办法,按推荐程度排序:
方案1:直接在按钮的onclick中写逻辑,无需定义函数
不用提前定义sendRequest函数,直接把跳转逻辑写在按钮的onclick属性里,完全避开脚本执行的问题:
htmlContent.append(String.format("<td><button type='button' onclick=\"window.location.href='updateRecorderInfoServlet?RecorderID=%s'\">%s</button></td>", recorderId, recorderId));
点击按钮时直接触发跳转,简单可靠,不需要依赖iframe里的脚本函数。
方案2:更新iframe内容后手动执行脚本
如果一定要保留函数定义的写法,在通过innerHTML插入内容后,需要手动提取并执行iframe中的脚本。修改JSP里的submitForm函数:
function submitForm() { var formData = new FormData(document.getElementById('displayForm')); fetch('getRecorderInfoServlet', { method: 'POST', headers: { 'Content-Type': 'text/plain' }, body: formData.get('Recorder_ID') }) .then(response => response.text()) .then(data => { const iframe = document.getElementById('resultFrame'); const iframeDoc = iframe.contentWindow.document; // 设置iframe内容 iframeDoc.body.innerHTML = data; // 提取并执行所有script标签 const scripts = iframeDoc.body.querySelectorAll('script'); scripts.forEach(oldScript => { const newScript = document.createElement('script'); newScript.textContent = oldScript.textContent; iframeDoc.head.appendChild(newScript); oldScript.remove(); }); }) .catch(error => console.error('Error:', error)); }
同时修正Servlet里脚本的语法错误:
htmlContent.append("<script>"); htmlContent.append("function sendRequest(RecorderID) {"); htmlContent.append(" var url = 'updateRecorderInfoServlet?RecorderID=' + RecorderID;"); // 补全单引号和分号 htmlContent.append(" console.log('Request URL:', url);"); htmlContent.append(" window.location.href = url;"); htmlContent.append("}"); htmlContent.append("</script>");
方案3:让Servlet返回完整HTML页面,设置iframe的src
这是最规范的做法:让getRecorderInfoServlet返回完整的HTML文档(包含<html>、<head>、<body>标签),然后在JSP里通过设置iframe的src属性加载内容,而非用innerHTML插入。
修改Servlet的响应:
response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<script>"); out.println("function sendRequest(RecorderID) {"); out.println(" var url = 'updateRecorderInfoServlet?RecorderID=' + RecorderID;"); out.println(" console.log('Request URL:', url);"); out.println(" window.location.href = url;"); out.println("}"); out.println("</script>"); out.println("</head>"); out.println("<body>"); // 拼接表格内容 out.println("<table>"); out.println(String.format("<tr><td><button type='button' onclick=\"sendRequest('%s')\">%s</button></td></tr>", recorderId, recorderId)); out.println("</table>"); out.println("</body>"); out.println("</html>");
修改JSP里的submitForm函数,直接设置iframe的src:
function submitForm() { const recorderId = document.getElementById('recorderId').value; // 用GET方式传递参数,自动编码避免特殊字符问题 document.getElementById('resultFrame').src = `getRecorderInfoServlet?Recorder_ID=${encodeURIComponent(recorderId)}`; }
同时调整Servlet的doGet方法处理参数(如果之前用的是doPost),这样浏览器会正常解析iframe中的HTML和脚本,函数能被正常调用。
内容的提问来源于stack exchange,提问作者DamanS

