这几天做一个项目的迭代开发,需要在react 中使用plupload 插件实现上传文件。需求很简单,如下图,点击“...” 按钮选择文件,点击“Import”按钮上传文件。
plupload 上传文件大概分为以下几步:
1. 新建一个uploader实例,并在构造时配置好上传的相关属性。
const uploader = new plupload.Uploader({
browse_button: 'selectFileId', //指定调起选择文件对话框的DOM 元素或其ID,注意是DOM元素
url: ‘put upload file url here’,
multi_selection: false,
init: { //在里面定义各种事件的回调
BeforeUpload: (uploader,file) => {
},
FilesAdded:(uploader,files)=>{
},
FileUploaded:(uploader,file,info) =>{
},
}
})
2. 初始化实例
this.uploader.init();
3. 在确定导入的按钮相关触发事件(例如onclick)的回调中调用实例的start方法,开始上传
handleImport = () => {
this.uploader.start();
}
但是在调试过程中问题一就出现了。
问题一:发现点击“...” 按钮无法调起选择文件对话框。跟踪发现init()函数也有被调用,说明uploader初始化没成功。反复检查配置,没发现配置有任何问题。既然配置没问题,那就可能是初始化的时机不对。检查发现,uploader的实例创建和init初始化都放在了 react component的 componentWillMount() 函数中。 突然醒悟,componentWillMount 是在react 创建的组件插入DOM节点之前触发的,也就是说调用时DOM中还没有ID为selectFlagId的元素,uploader 初始化时当然是找不到触发DOM的。谜底解开。。。
问题一解决后,接着测试,又发现了问题二。
问题二:当第一次触发上传,服务端检查发现文件内容不符合规范,返回错误。这个时候,用户直接打开文件修改保存,再在界面直接点击上传按钮,发现无法上传文件,但是重新选择文件后,又可以上传。打开chrome 开发工具,检查网络请求,发现无上传请求发出。然后设断点跟踪,发现handleImport() 函数是调用了的,uploader 的start 函数也是调用了的,但是BeforeUpload函数没有进入。也就是说是uploader 在接受到start信号后,没有触发上传。此刻小编脑上各种⭕️, 到这里,就需要去了解pluploader内部的上传机制了。打开plupload 官方文档查阅,发现在plupload内部有一个上传队列,每次选择文件后,都会把文件放入队列中,每次start时,都会从队列中拿任务。但是由于第一上传已经触发,任务已经执行;第二次点击时,任务队列其实是空的,拿不到任务,自然不会上传;如果再次选择文件,文件又会被放入队列,因此可以拿到任务,进行上传。谜底揭晓了。
那问题来了,怎么解决呢?
首次需求是要满足的,不能要求用户一定要再选一次文件吧,毕竟用户是我们的衣食父母啊;
其次