最近在寫一個OJ網(wǎng)站,里面要用到upload的地方比較多,然后需要對upload進(jìn)行封裝,其中還用到了form,由于遇到了幾個比較隱蔽的問題,而耽誤了幾天,為了讓廣大猿媛們少走彎路,這里講一下自己的封裝過程。
這里提一個比較的需求,就是實(shí)現(xiàn)手動上傳并且獲得上傳后的路徑。
涉及解決的問題
將數(shù)據(jù)返回給父組件
重寫上傳操作,也就是寫customRequest
重寫刪除操作, handleRemove
控制是否顯示上傳列表, showUploadList
用于form
- 首先定義存儲數(shù)據(jù)和刷新界面的state和props
constructor(p) {
super(p);
this.state = {
uploadedFileList: [], // 已經(jīng)上傳的文件列表
// uploadedFilePaths: [] // 已經(jīng)上傳的文件路徑
};
}
static propTypes = {
showUploadList: PropTypes.bool,
beforeUpload: PropTypes.func,
customUpload: PropTypes.func,
onRemove: PropTypes.func
}
static defaultProps = {
saveType: 'file', // 保存的類型,默認(rèn)為file, 可選的值有 'file','base64','redis'
fileList: [], // 默認(rèn)的上傳的文件, 格式為 fileList: [{uid: '對應(yīng)文件的uid', name: '文件名稱', status: 'done', url: '文件url'}]
showUploadList: true, // 是否顯示上傳的文件列表
onChange: ()=> {}, // 文件值改變的時候的回調(diào)函數(shù)
// beforeUpload: null, // 文件上傳之前的檢驗(yàn)
// customUpload: null, // 手動進(jìn)行上傳文件
// onRemove: ()=> {}, // 成功刪除的回調(diào)函數(shù)
}
- 寫手動上傳的函數(shù)
customUpload= (file) => {
request.post(`${prefix}/teacher/course/upload`)
.attach('files', file.file)
.field({from: 'customUpload'}).then(result=> {
const uploadedFileList = this.props.value;
const newFile = {uid: file.file.uid, name: file.file.name, url: result.body.data};
let fileList = [];
if (uploadedFileList) {
uploadedFileList.map((e) => {
return fileList.push(e);
});
}
fileList.push(newFile);
this.setState({
uploadedFileList: [...fileList]
});
// 父組件監(jiān)聽數(shù)據(jù)變化
const {onChange} = this.props;
onChange(fileList); // 父組件的onChange只會去更改value的值
});
}
- 寫刪除函數(shù),然后將數(shù)據(jù)變化提交給父組件
handleRemove= (file) => {
const uploadedFileList = this.state.uploadedFileList.slice();
const index = uploadedFileList.indexOf(file);
const [bucket, objectName] = uploadedFileList[index].url.split('/');
request.delete(`${prefix}/teacher/course/remove`)
.query({
bucket,
objectName
})
.then(result => {
if (result.body.code !== 'SUCCESS') {
return;
}
uploadedFileList.splice(index, 1);
this.setState({
uploadedFileList
});
// 將數(shù)據(jù)返回給父組件處理
const {onChange} = this.props;
let fileList = [];
uploadedFileList.map((e) => {
return fileList.push(e);
});
onChange(fileList);
});
}
- 將上面的函數(shù)綁定到Upload組件中
<Upload
fileList={this.state.uploadedFileList}
beforeUpload={this.beforeUpload}
customRequest={this.customUpload}
onRemove={this.handleRemove}
// onChange={this.handleChange}
{...uploadProps}>
<Button><Icon type='upload'></Icon>上傳文件</Button>
</Upload>
至此,只需要將這個組件export出去就完成了封裝,比如,我們這個組件叫customUpload,則如下
export default CustomUpload;
上述過程有點(diǎn)看起來很簡單,但是有幾個注意點(diǎn),如下:
-
upload中customRequest不能夠使用async關(guān)鍵字,如果需要向服務(wù)器發(fā)送請求,又想接收返回值做出相應(yīng)操作, 有兩個方式,一個是使用dispatch,一個就是使用.then的方法。如果使用了async關(guān)鍵字,在組件銷毀的時候會報一個reqs[uid].abort的錯誤,需要注意! - 在form組件中,使用的是
getFieldDecorator進(jìn)行渲染組件的,這個時候它會往組件中注入value這一個屬性和onChange這個函數(shù)用于存儲值和監(jiān)聽值的改變,所以在封裝的組件中,需要調(diào)用this.props.onChange方法來對希望改變的值進(jìn)行操作。
以上!希望對大家有所幫助。
注:上述表述如有錯誤,請各位不吝賜教!