最近,小明遇到這樣一種狀況:在網頁中上傳文件時偶爾頁面會崩潰。小明仔細測試了這種狀況,發現以前用的一個文件上傳組件有一點缺陷,因而,小明決定本身手寫一個,樣式以下:css
圖一是沒有上傳文件時的樣式,圖二爲上傳文件後的樣式。虛線部分爲放置區域,先來看代碼:html
<div id="app"> <div class="content"> <div class="drag-area" @dragover="fileDragover" @drop="fileDrop"> <div v-if="fileName" class="file-name">{{ fileName }}</div> <div v-else class="uploader-tips"> <span>將文件拖拽至此,或</span> <label for="fileInput" style="color: #11A8FF; cursor: pointer">點此上傳</label> </div> </div> </div> <div class="footer"> <input type="file" id="fileInput" @change="chooseUploadFile" style="display: none;"> <label for="fileInput" v-if="fileName" style="color: #11A8FF; cursor: pointer">選擇文件</label> <button @click="uploadOk">提交</button> </div> </div>
* { font-size: 14px; } .drag-area { height: 200px; width: 300px; border: dashed 1px gray; margin-bottom: 10px; color: #777; } .uploader-tips { text-align: center; height: 200px; line-height: 200px; } .file-name { text-align: center; height: 200px; line-height: 200px; }
new Vue({ el: '#app', data () { return { fileName: '', batchFile: '', MAX_FILE_SIZE: 10 * 1000 * 1000 } }, methods: { // 點擊上傳 chooseUploadFile (e) { const file = e.target.files.item(0) if (!file) return if (file.size > this.MAX_FILE_SIZE) { return alert('文件大小不能超過10M') } this.batchFile = file this.fileName = file.name // 清空,防止上傳後再上傳沒有反應 e.target.value = '' }, // 拖拽上傳 fileDragover (e) { e.preventDefault() }, fileDrop (e) { e.preventDefault() const file = e.dataTransfer.files[0] // 獲取到第一個上傳的文件對象 if (!file) return if (file.size > this.MAX_FILE_SIZE) { return alert('文件大小不能超過10M') } this.batchFile = file this.fileName = file.name }, // 提交 uploadOk () { if (this.batchFile === '') { return alert('請選擇要上傳的文件') } let data = new FormData() data.append('upfile', this.batchFile) // ajax } } })
第一個要說的就是拖拽中的這兩個事件,由於這兩個事件撐起了拖拽上傳的核心功能。
對於拖拽這個動做而言,有二個核心概念,一個是拖拽元素
,還一個是放置目標
。這裏,我只講放置目標上的事件,對於拖拽元素的事件,請自行查閱。ajax
那對於放置目標,它有什麼事件呢?以下:
當某個元素被拖動到一個有效的放置目標上(如上例中虛線區域)時,下列事件會依次發生:
(1) dragenter
(2) dragover
(3) dragleave 或 drop
只要有元素被拖動到放置目標上,就會觸發 dragenter 事件(相似於 mouseover 事件)。緊隨其後的是 dragover 事件,並且在被拖動的元素還在放置目標的範圍內移動時,就會持續觸發該事件。若是元素被拖出了放置目標,dragover 事件再也不發生,但會觸發 dragleave 事件(相似於 mouseout事件)。若是元素被放到了放置目標中,則會觸發 drop 事件而不是 dragleave 事件。服務器
對於本例來講,咱們只須要關注dragover和drop事件。可是drop事件卻有點調皮,你想監聽它,還得進行一些處理,由於默認狀況下,元素是不容許放置的,在拖動元素通過某些無效放置目標時,能夠看到一種特殊的光標(圓環中有一條反斜線),表示不能放置。以下:
若是拖動元素通過不容許放置的元素,那不管用戶如何操做,都不會發生 drop 事件。那怎麼辦呢?
咱們能夠重寫 dragover 事件的默認行爲,如上例代碼中的e.preventDefault()
。
細心的同窗可能要問了,那drop事件中也有e.preventDefault()
,去掉行不行呢?你們能夠自行試下。app
可能這個對象看着有些陌生,可是它的做用可不小。好比,你拖動一個圖片到目標區域,那目標區域怎麼獲取這個圖片的信息呢?就靠它!它是事件對象的一個屬性,用於從被拖動元素向放置目標傳遞字符串格式的數據。在本例中,咱們能夠經過它來獲取拖動中的文件信息。測試
這個事件其實有坑的,它有這樣一個特性,即:上傳同一個文件,並不會觸發change事件,即便該文件內容作過修改。
細思極恐!好比,用戶要上傳一個文檔,可是拖拽到虛線區域後發現文檔內容還須要修改下,他改完後再拖拽該文檔,再提交到服務器,那麼他上傳到服務器的文檔內容倒是未修改以前的!
因此,咱們須要代碼e.target.value = ''
來進行重置處理,這樣,每次上傳文件都會觸發change事件。this