怎么使用vue實現上傳組件
今天小編給大家分享一下怎么使用vue實現上傳組件的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
思路
文件上傳的兩種實現方式
1.From形式
<form? ??method="post"? ??enctype="multipart/from-data" ??action="api/upload" > ??<input?type="file?name="file"> ??<button?type="submit">Submit</button> </form>
form的method屬性指定為 "post" 請求,通過HTML表單發送數據給服務器,并返回服務器的修改結果,在這種情況下Content-Type是通過在<form>元素中設置正確的enctype屬性。
form的enctype屬性規定在發送到服務器之前應該如何對表單數據進行編碼。
application/x-www-form-urlencoded(默認值):表示在發送前編碼所有字符,數據被編碼成以"&"分隔的鍵值對,同時以"="分隔鍵和值,("name=seven&age=19")。不支持二進制數據。
multipart/form-data:支持二進制數據(上傳文件時必須指定)
2.JavaScript異步請求形式
我們知道 FormData 接口提供了一種表示表單數據的鍵值對 key/value 的構造方式,并且可以輕松的將數據通過XMLHttpRequest.send()方法發送出去,本接口和此方法都相當簡單直接。如果送出時的編碼類型被設為 "multipart/form-data",它會使用和表單一樣的格式。
var?formdata?=?new?FormData();?//?創建FormData對象 formdata.append("name","laotie");?//?通過append()方法添加新的屬性值 ...?//?更多方法請點下面鏈接
FormData接口
生命周期
上傳組件也有它的生命周期
beforeUpload --> uploading --> fileUploaded 或者 uploadedError
代碼草稿
本例中采用js異步請求的方式開發上傳組件
<input?type="file"?name="file"?@change.prevent="handleFileChange"> //?創建一個file類型的input,用于觸發文件上傳,后面可以把input隱藏掉,自定義好看的樣式 //?自定義樣式的時候可以用slot區分不同上傳狀態的樣式(loading,success,defult)
const?handleFileChange?=?(e:Event)=>{ ??const?target?=?e.target?as?HTMLInputElement ??const?files?=?Array.from(target.files)//?注意這里取得的是一個類數組 ??if(files){ ????//?取得文件 ????const?uploadedFile?=?files[0] ???? ????if(!validateFormat)?return ????//?...這里只是提供一種思路,具體校驗不再講述 ????//?在這里做一些上傳文件前的校驗,比如文件格式,大小等, ????//?不符合要求的話就不在繼續發送請求 ???? ????const?formData?=?new?FormData() ????formData.append(uploadedFile.name,uploadedFile) ???? ????axios.post('/upload',formData,{ ??????headers:{ ?????????//?注意設置編碼類型 ????????'Content-Type':?'multipart/form-data' ??????} ????}).then(res=>{ ??????console.log('上傳成功') ????}).catch(error?=>{ ??????//?文件上傳失敗 ????}).finally(()=>{ ??????//?文件上傳完成,無論成功還是失敗 ??????//?這里可以清除一下input.value ????}) ??} }
具體實現
//?Upload.vue <template> ??<div> ????<div?@click.prevent="triggerUpload"?v-bind="$attrs"> ??????<slot?name="loading"?v-if="fileStatus==='loading'"> ????????<button?class="btn?btn-primary">上傳中</button> ??????</slot> ??????<slot?name="uploaded"?v-else-if="fileStatus==='success'"?:uploadedData="fileData"> ????????<button?class="btn?btn-primary">上傳成功</button> ??????</slot> ??????<slot?v-else?name="default"> ????????<button?class="btn?btn-primary">點擊上傳</button> ??????</slot> ????</div> ????<input?type="file"?class="file-input?d-none"?name="file"?ref="uploadInput"?@change="hanldeInput"/> ??</div> </template> <script> import?{?defineComponent,?ref,?PropType,?watch?}?from?'vue' import?axios?from?'axios' type?UploadStatus?=?'ready'?|?'loading'?|?'success'?|?'error' type?FunctionProps?=?(file:File)?=>?boolean export?default?defineComponent({ ??name:?'Upload', ??inheritAttrs:?false, ??props:?{ ????//?上傳的url ????action:?{ ??????type:?String, ??????required:?true ????}, ????//?上傳之前的校驗,是一個返回布爾值的函數 ????beforeUpload:?{ ??????type:?Function?as?PropType<FunctionProps> ????}, ????//?上傳好的數據,用來判斷狀態或做初始化展示 ????uploadedData:?{ ??????type:?Object ????} ??}, ??emits:?['file-uploaded-success',?'file-uploaded-error'], ??setup(props,?ctx)?{ ????const?uploadInput?=?ref<null?|?HTMLInputElement>(null) ????const?fileStatus?=?ref<UploadStatus>(props.uploadedData???'success'?:?'ready') ????const?fileData?=?ref(props.uploadedData) ????watch(()?=>?props.uploadedData,?(val)?=>?{ ??????if?(val)?{ ????????fileStatus.value?=?'success' ????????fileData.value?=?val ??????} ????}) ????const?triggerUpload?=?()?=>?{ ??????if?(uploadInput.value)?{ ????????uploadInput.value.click() ??????} ????} ????const?hanldeInput?=?(e:Event)?=>?{ ??????const?target?=?e.target?as?HTMLInputElement ??????const?files?=?target.files ??????console.log(target) ??????if?(files)?{ ????????const?uploadFile?=?Array.from(files) ????????const?validateFormat?=?props.beforeUpload???props.beforeUpload(uploadFile[0])?:?true ????????if?(!validateFormat)?return ????????fileStatus.value?=?'loading' ????????const?formData?=?new?FormData() ????????formData.append('file',?uploadFile[0]) ????????axios.post(props.action,?formData,?{ ??????????headers:?{ ????????????'Content-Type':?'multipart/form-data' ??????????} ????????}).then(res?=>?{ ??????????console.log('文件上傳成功',?res) ??????????fileStatus.value?=?'success' ??????????fileData.value?=?res.data ??????????ctx.emit('file-uploaded-success',?res.data) ????????}).catch(error?=>?{ ??????????console.log('文件上傳失敗',?error) ??????????fileStatus.value?=?'error' ??????????ctx.emit('file-uploaded-error',?error) ????????}).finally(()?=>?{ ??????????console.log('文件上傳完成') ??????????if?(uploadInput.value)?{ ????????????uploadInput.value.value?=?'' ??????????} ????????}) ??????} ????} ????return?{ ??????uploadInput, ??????triggerUpload, ??????hanldeInput, ??????fileStatus, ??????fileData ????} ??} }) </script>
使用示例:
<template> ??<div> ????<upload ??????action="/upload" ??????:beforeUpload="beforeUpload" ??????:uploadedData="uploadedData" ??????@file-uploaded-success="hanldeUploadSuccess" ??????class="d-flex?align-items-center?justify-content-center?bg-light?text-secondary?w-100?my-4" ??????> ??????<template?#uploaded="slotProps"> ????????<div> ??????????<img?:src="slotProps.uploadedData.data.url"/> ??????????<h4>點擊重新上傳</h4> ????????</div> ???????</template> ???????<template?#default> ?????????<h3>點擊上傳頭圖</h3> ???????</template> ???????<template?#loading> ?????????<div> ??????????<div?class="spinner-border?text-secondary"?role="status"> ????????????<span></span> ??????????</div> ?????????</div> ???????</template> ????</upload> ??</div> </template> <script> import?{?defineComponent,?ref,?onMounted?}?from?'vue' import?Upload?from?'../components/Upload.vue' import?createMessage?from?'../components/createMessage' export?default?defineComponent({ ??name:?'CreatePost', ??components:?{?Upload?}, ??setup()?{ ????const?uploadedData?=?ref()?//創建一個響應式數據 ????let?imageId?=?'' ????onMounted(()?=>?{ ??????.... ??????//?這里有邏輯省略了,取到初始化數據image ??????if?(image)?{ ????????uploadedData.value?=?{?data:?image?} ??????} ????}) ????//?上傳前校驗,返回布爾值 ????const?beforeUpload?=?(file:File)?=>?{ ??????const?res?=?beforeUploadCheck(file,?{ ????????format:?['image/jpeg',?'image/png'], ????????size:?1 ??????}) ??????const?{?error,?passed?}?=?res ??????if?(error?===?'format')?{ ????????createMessage('上傳圖片只能是JPG/PNG格式!',?'error') ??????} ??????if?(error?===?'size')?{ ????????createMessage('上傳圖片大小不能超過1MB',?'error') ??????} ??????return?passed ????} ????//?上傳成功后拿到imageId就可以進行后續處理,創建表單啥的 ????const?hanldeUploadSuccess?=?(res:ResponeseProps<ImageProps>)?=>?{ ??????createMessage(`上傳圖片ID?${res.data._id}`,?'success') ??????if?(res.data._id)?{ ????????imageId?=?res.data._id ??????} ????} ????return?{ ??????beforeUpload, ??????hanldeUploadSuccess, ??????uploadedData ????} ??} }) </script> <style> .create-post-page{ ??padding:0?20px?20px; } .create-post-page?.upload-box{ ??height:200px; ??cursor:?pointer; ??overflow:?hidden; } .create-post-page?.upload-box?img{ ??width:?100%; ??height:?100%; ??object-fit:?cover; } .uploaded-area{ ??position:?relative; } .uploaded-area:hover?h4{ ??display:?block; } .uploaded-area?h4{ ??display:?none; ??position:?absolute; ??color:?#999; ??text-align:?center; ??width:?100%; ??top:50% } </style>
以上就是“怎么使用vue實現上傳組件”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注蝸牛博客行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:niceseo99@gmail.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。
評論