Angular5/TypeScript项目IE9下无Ajax/jQuery的FormData兼容方案
嘿,这个IE9的FormData问题确实挺头疼的,毕竟它是个老古董了,而且你不想用jQuery和Ajax,那我给你两个靠谱的纯原生解决方案:
方案一:添加FormData Polyfill(贴近现代代码逻辑)
IE9原生压根没有FormData构造函数,我们可以自己加一个轻量的纯JS polyfill,完全不依赖第三方库。
步骤1:引入Polyfill
把这段代码添加到你的项目polyfills.ts文件里(或者在组件加载前执行):
if (typeof FormData === 'undefined') { window.FormData = function() { const formData = {}; const boundary = '----FormDataPolyfill' + Math.random(); this.append = function(key, value, filename) { formData[key] = { value: value, filename: filename || key }; }; this.toString = function() { const parts = []; for (const key in formData) { if (formData.hasOwnProperty(key)) { const item = formData[key]; parts.push('--' + boundary); if (item.value instanceof File) { // IE9的File对象支持getAsBinary方法获取文件内容 parts.push('Content-Disposition: form-data; name="' + key + '"; filename="' + item.filename + '"'); parts.push('Content-Type: ' + (item.value.type || 'application/octet-stream')); parts.push(''); parts.push(item.value.getAsBinary()); } else { parts.push('Content-Disposition: form-data; name="' + key + '"'); parts.push(''); parts.push(item.value); } } } parts.push('--' + boundary + '--'); parts.push(''); return parts.join('\r\n'); }; this.getBoundary = function() { return boundary; }; }; }
步骤2:调整请求发送逻辑
因为IE9的XMLHttpRequest不能直接发送原生FormData(我们的polyfill是自定义的),所以要手动设置请求头并处理发送内容:
// 假设这是你的上传请求逻辑 sendUploadRequest() { const xhr = new XMLHttpRequest(); xhr.open('POST', '/你的上传接口地址', true); // 判断是否用的是我们的polyfill,手动设置Content-Type if (typeof (this.formCvData as any).getBoundary === 'function') { xhr.setRequestHeader( 'Content-Type', 'multipart/form-data; boundary=' + (this.formCvData as any).getBoundary() ); } xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { // 处理上传成功的逻辑 console.log('上传成功'); } else { // 处理上传失败的逻辑 console.error('上传失败'); } } }; // 发送请求,polyfill的情况发送toString后的内容,否则正常发送FormData xhr.send( typeof (this.formCvData as any).getBoundary === 'function' ? (this.formCvData as any).toString() : this.formCvData ); }
方案二:用隐藏iframe模拟异步上传(原生兼容IE9)
如果不想折腾polyfill,这个方案更贴合IE9的原生能力,利用表单提交到隐藏iframe来实现无刷新上传:
步骤1:修改组件模板
给表单添加target属性指向隐藏的iframe,同时新增这个隐藏iframe:
<form #formUpload id="formUpload" target="uploadFrame" method="POST" enctype="multipart/form-data" action="/你的上传接口地址" > <input type="file" class="input-file-ghost" (change)="onChangeFile($event.target.files)"> <!-- 隐藏的iframe,用来接收表单提交结果 --> <iframe name="uploadFrame" style="display: none;" (load)="onIframeLoad($event)"></iframe> </form>
步骤2:调整组件TS逻辑
去掉FormData相关代码,直接提交表单,并监听iframe的加载事件获取上传结果:
export class UploadFileComponent implements OnInit { @Input() uploadFileConfig: any; @Output() filesAdded = new EventEmitter<any>(); @ViewChild('formUpload') formUpload: ElementRef; constructor() { } ngOnInit() { } onChangeFile(files: File[]) { // 直接提交表单,结果会在隐藏iframe里返回 this.formUpload.nativeElement.submit(); } onIframeLoad(event: Event) { const iframe = event.target as HTMLIFrameElement; const response = iframe.contentDocument?.body?.textContent; try { // 解析服务器返回的JSON响应(如果服务器返回的是JSON) const result = JSON.parse(response || '{}'); // 通过事件通知父组件上传结果 this.filesAdded.emit(result); } catch (e) { console.error('解析响应失败:', e); } // 重置表单,支持再次上传 this.formUpload.nativeElement.reset(); } }
注意事项
- 确保你的Angular5项目已经配置了IE9所需的基础polyfills(比如
core-js/es6相关内容),不然Angular本身的代码在IE9里跑不起来。 - 服务器端要支持传统表单上传的方式接收文件(和接收FormData的逻辑基本一致,大部分后端框架都兼容)。
内容的提问来源于stack exchange,提问作者LYES - CHIOUKH
相关产品推荐
相关产品推荐

