iframe 标签和定时调用函数 setInterval
- 问题描述:
- 解决方法:
问题描述:
今天遇到一个前端问题,在浏览器页面上传Excel
文件后,然后点击导入按钮,经后端Java
类读取文件内容校验后,将校验结果返回给前端,要求整个校验过程中,整个界面禁止跳转,校验结果以弹框形式展示,然后用户根据校验结果,选择【确定】或【取消】决定是否真正导入该 Excel
文件数据;
项目中导入文件时使用的 form.submit();
方法,form
表单属性enctype="multipart/form-data"
,通过这种方式将 内置的参数 传入到后端,后端根据这些参数来解析Excel
文件获取数据来校验,因为项目框架限制,无法使用 FormData
工具、Promise
、传统Ajax
方式…(要不无法使用,可以使用的无法将解析 Excel 文件的关键内置参数传入后端
)
界面参考:
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>文件上传界面</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4; /* 背景颜色 */
margin: 0;
padding: 0;
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 100vh; /* 全屏高度 */
}
.container {
background-color: white; /* 内容区域背景色 */
padding: 30px; /* 上下内边距,增加容器高度 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */
text-align: center; /* 文字居中 */
width: 80%; /* 宽度 */
max-width: 600px; /* 最大宽度 */
min-height: 300px; /* 最小高度,容器高度增加 */
}
h1 {
color: #333; /* 标题颜色 */
margin-bottom: 20px; /* 标题底部留白 */
}
p {
color: #666; /* 文字颜色 */
margin-bottom: 20px; /* 段落底部留白 */
}
.file-upload {
display: flex; /* 使用 flexbox 放置文件选择、文件名框和上传按钮 */
align-items: center; /* 垂直居中 */
justify-content: flex-start; /* 左对齐 */
gap: 10px; /* 之间留白 */
}
.file-upload input[type="file"] {
flex: 1; /* 文件选择框占据剩余空间 */
display: none; /* 隐藏文件选择框 */
}
.file-upload .file-name {
width: 100%; /* 文件名框占满空间 */
padding: 10px;
border: 1px solid #ccc; /* 边框 */
border-radius: 5px; /* 圆角 */
text-align: left; /* 文件名显示在左侧 */
background-color: #f9f9f9; /* 背景颜色 */
height: 40px; /* 高度统一 */
}
.choose-file-btn,
.upload-btn {
padding: 10px 20px; /* 按钮内边距 */
border: none; /* 无边框 */
border-radius: 5px; /* 圆角 */
cursor: pointer; /* 鼠标指针样式 */
height: 40px; /* 高度一致 */
white-space: nowrap; /* 防止文字换行 */
}
.choose-file-btn {
background-color: #007bff; /* 选择文件按钮的蓝色 */
color: white; /* 按钮文字颜色 */
}
.choose-file-btn:hover {
background-color: #0056b3; /* 蓝色按钮悬停效果 */
}
.upload-btn {
background-color: #28a745; /* 上传按钮的绿色 */
color: white; /* 按钮文字颜色 */
}
.upload-btn:hover {
background-color: #218838; /* 绿色按钮悬停效果 */
}
</style>
</head>
<body>
<div class="container">
<h1>欢迎来到文件导入界面</h1>
<p>请在下面上传您的文件。</p>
<form id="myForm" action="upload" method="post" enctype="multipart/form-data">
<div class="file-upload">
<input type="text" id="fileName" class="file-name" placeholder="请选择文件..." readonly>
<input type="file" name="file" id="fileInput" required onchange="updateFileName()">
<button type="button" class="choose-file-btn" onclick="document.getElementById('fileInput').click();">选择文件</button>
<input type="submit" class="upload-btn" value="导入">
</div>
</form>
<iframe name="upload_target" style="display:none;"></iframe>
</div>
<script>
// 显示选择的文件名
function updateFileName() {
let fileInput = document.getElementById('fileInput');
let fileNameField = document.getElementById('fileName');
if (fileInput.files.length > 0) {
fileNameField.value = fileInput.files[0].name;
}
}
</script>
</body>
</html>
解决方法:
要求整个校验过程中,整个界面禁止跳转 这一过程可以通过 <iframe>
标签来实现;
获取校验结果可以通过定时调用函数setInterval
来实现。(因为异步提交表单导致获取校验结果的代码总是先结果返回之前执行,一直获取空,所以才采用定时调用函数setInterval
来实现)
IFRAME
是HTML
标签,作用是文档中的文档,或者浮动的框架(FRAME
)。iframe
元素会创建包含另外一个文档的内联框架(即行内框架)
setInterval
是一个实现定时调用的函数,可按照指定的周期(以毫秒
计)来调用函数或计算表达式。setInterval
方法会不停地调用函数,直到clearInterval
被调用或窗口被关闭。
- 由
setInterval
返回的ID
值可用作clearInterval
方法的参数。
示例代码:
function doImport() {
let form = document.forms["myForm"];//获取name属性值为"myForm"的表单对象
let ckUrl = 'XXXXXXX';//校验地址
// 设置表单的目标属性为 'upload_target',即指定表单提交后显示的iframe
form.setAttribute('target', 'upload_target');
form.action = ckUrl; // 设置表单提交的URL地址
form.submit();// 提交表单
// 启动一个定时器,每200毫秒检查一次iframe内容
const start = setInterval(function () {
let ifm = document.getElementById('ifm'); // 获取iframe元素
let ifDoc = ifm.contentDocument || ifm.contentWindow.document;// 获取iframe内部的文档对象
let ifContent = ifDoc.body.innerHTML; // 获取iframe文档中的HTML内容
// 判断iframe中的内容是否为空,如果不为空则执行以下操作
if (ifContent !== '') {
doStopGoal(); // 停止定时器
let returnData = eval('(' + ifContent + ')');// 解析iframe中的内容
let ckInfo = returnData.ckInfo;// 获取返回的数据中的ckInfo字段值
if (ckInfo === 'ok') {//校验通过,调用导入函数
importConfirm();
} else {
//逻辑代码...
}
}
}, 200); // 每200毫秒执行一次
// 停止定时器
function doStopGoal() {
clearInterval(start);
}
}
// 校验成功后,真正导入数据
function importConfirm() {
let importUrl = 'YYYYYY'; // 导入地址
let form = document.forms["myForm"];
form.removeAttribute("target");// 移除表单的target属性
form.action = importUrl;
form.submit();
}