Safari浏览器中如何将File对象赋值给type=file类型的input元素
解决方案
你遇到的问题来自两个层面:代码本身的参数错误,以及Safari对input[type=file]的files属性赋值的安全限制,下面给出具体修复方案:
一、先修复现有代码的基础错误
现有代码的几个错误会直接导致功能在所有浏览器都可能出现异常,优先修复:
- 修正文件类型返回值,
openFile函数需要返回完整MIME类型而非后缀名,供canvas.toBlob使用:
function openFile(file) { var extension = file.substr( (file.lastIndexOf('.') +1) ).toLowerCase(); switch(extension) { case 'jpg': case 'jpeg': return 'image/jpeg' case 'png': return 'image/png' default: return '1' } };- 修正文件类型返回值,
- 修正File对象创建时的type参数:
// 原来的错误写法:type写死为"mime/type" // let file2 = new File([blob], new_file_name, {type:"mime/type", lastModified:new Date().getTime()}); // 修正后:用实际的MIME类型 let file2 = new File([blob], new_file_name, {type: MIME_TYPE, lastModified:new Date().getTime()});- 补充
QUALITY的默认值,避免超出大小限制场景下参数异常:
var QUALITY = 0.9; // 先给默认值 if (FileSize >= 8000000) { // 原有报错逻辑不变 }- 补充
二、解决Safari下无法给input赋值的问题
这里给两种可选方案,优先选第一种,兼容性最好:
方案1:绕开input赋值,直接用FormData提交(推荐)
浏览器限制input的files属性赋值本质是安全策略,你完全不需要第二个隐藏的input存压缩后的文件,直接全局存储压缩后的File对象,提交时塞进FormData即可,兼容所有浏览器,后端逻辑无需修改:
- 先定义全局变量存压缩后的文件
// 放在脚本顶部 let compressedImageFile = null;
- 压缩生成file2后,不要赋值input,直接存到全局变量
// 替换原有给bt_current_file赋值的逻辑 compressedImageFile = file2;
- 表单提交时,把压缩后的文件塞入FormData
function submitUploadForm() { const form = document.getElementById('你的表单ID'); const formData = new FormData(form); // 删除原input上传的未压缩文件,替换为压缩后的文件 formData.delete('file_dep'); formData.append('file_dep', compressedImageFile); // 用fetch/axios提交formData即可,后续上传到GCS的逻辑完全不变 fetch('/你的上传接口地址', { method: 'POST', body: formData }).then(res => res.json()).then(result => { // 处理上传结果 }) }
方案2:兼容Safari的input赋值写法
如果你一定要保留给input赋值的逻辑,可以加兼容判断:
let fileInputElement = document.getElementById('bt_current_file'); try { // 高版本Safari/Chrome/Firefox走该逻辑 const container = new DataTransfer(); container.items.add(file2); fileInputElement.files = container.files; } catch (err) { // 低版本Safari走兼容逻辑,将文件挂到input自定义属性上,提交时取该值 fileInputElement._customFiles = [file2]; // 提交表单时优先取_customFiles属性的值塞入FormData即可 }
三、可选优化点
现有calculateSize函数直接固定宽高会导致图片拉伸变形,建议改为等比缩放:
function calculateSize(img, maxWidth, maxHeight) { let width = img.width; let height = img.height; // 计算缩放比例,取最小的比例保证图片不超出最大限制 const ratio = Math.min(maxWidth / width, maxHeight / height); return [width * ratio, height * ratio]; }
内容的提问来源于stack exchange,提问作者Cracker Rex
相关产品推荐
相关产品推荐

