使用jQuery clone复制图片时如何为file类型input字段赋值
问题核心原因
你现有代码无法正常复制文件值,本质是两个问题:
- jQuery对象没有原生DOM的
files属性,你写的$(selector).files永远返回undefined,根本拿不到选中的文件 - jQuery的
clone()方法只会复制DOM结构,不会复制file input上绑定的选中文件;同时浏览器出于安全限制,禁止直接给file input赋值字符串路径,只能传入合法的FileList对象。
具体修复方案
新建帖子场景的代码修正
把你原来绑定下拉选项点击的逻辑替换成下面的代码,通过原生API拿到源文件,再用DataTransfer对象给克隆后的input注入文件:
// 推荐用事件委托,只需要在页面加载时绑定一次,不用每次新增块都重复绑定 $(document).on("click", ".image_dd li", function () { const $currentLi = $(this); const targetLangId = $currentLi.attr("id"); const $sourceBlock = $currentLi.closest(".qwer"); // 转原生DOM对象拿文件列表 const sourceFileInput = $sourceBlock.find(".imageblock")[0]; const sourceFileList = sourceFileInput.files; // 克隆DOM节点 const $clonedBlock = $sourceBlock.clone(true); const $clonedInput = $clonedBlock.find("input.imageblock"); // 先修改克隆后input的name属性,匹配目标语言的提交格式 $clonedInput.attr("name", `data[${targetLangId}][imageblock${k}]`); // 源input有选中文件时,通过DataTransfer把文件赋值给新input if (sourceFileList.length > 0) { const transfer = new DataTransfer(); Array.from(sourceFileList).forEach(file => { transfer.items.add(file); }); $clonedInput[0].files = transfer.files; } $clonedBlock.appendTo(`#dynamic${targetLangId}`); k++; alert("Duplicated"); });
注意:你原来把li的点击事件绑定写在.imageblockbtn的点击回调里,每次新增块都会给所有下拉选项重复绑定事件,容易造成重复触发,用上面的事件委托写法可以避免这个问题。
编辑帖子场景的兼容处理
编辑场景要分两类图片处理,不要硬给input塞不存在的文件:
- 本次进入编辑页后用户新选的图片:上面的逻辑已经可以正常复制,提交表单时后端能直接拿到新上传的文件
- 帖子原本就存在的旧图片:这类图片不会出现在file input的files列表里,不需要强行转成文件上传,只需要在渲染旧图片块的时候,加一个隐藏input存旧图的存储路径/数据库ID就行,示例:
<input type="hidden" class="old-image-path" name="data[{{$langId}}][old_image{{$imgKey}}]" value="{{$oldImage->storage_path}}">
克隆块的时候这个隐藏input会被一起复制,你只需要同步修改隐藏input的name属性匹配目标语言即可。后端Laravel处理提交数据时,优先判断对应位置有没有新上传的file,有就走新文件存储逻辑,没有就取隐藏input传的旧图路径做关联,不需要重复存储相同的图片。
额外注意点
- 你现在动态插入的图片块都用了固定id
imageblock,多块共存时会出现ID重复的DOM规范问题,建议把块ID改成和k值绑定的动态值,比如imageblock-${k} - DataTransfer接口所有现代浏览器都支持,如果你需要兼容IE11及更早版本,得换formData拼接的方案,常规Laravel项目一般不需要兼容这么老的浏览器
- 如果后续要做多图上传,上面的文件复制逻辑不需要修改,本身就支持多文件遍历赋值
内容的提问来源于stack exchange,提问作者ezio
相关产品推荐
相关产品推荐

