input type="file"使用

深藍一人發表於2018-03-17

問題:

在實際開發過程中,會遇到上傳檔案的一些需求。但是使用原生的<input type="file" />在使用中存在一些問題

  • 在未上傳檔案時,顯示"no file choosen",使用者介面不友好,不可配置
  • 上傳同一個檔案,不會觸發change事件,即使該檔案做過修改
  • 使用者如果在上傳過程中點選了“取消”,已經上傳的檔案會被移除

解決思路

在閱讀了一些原始碼之後,總結了如下的解決方案。有點偷樑換柱的意思:

  • 將真正的<input type="file" />隱藏,使用自定義的button通過$refs去觸發檔案上傳,實現自定義顯示
  • 檔案上傳之後,處理完檔案,將<input type="file" />value設定為null,這樣下次即使上傳的是同一個檔案,仍然會觸發change事件
  • 使用上述方法,點選取消檔案被移除,但是不影響頁面展示

具體實現

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="https://unpkg.com/vue"></script>
    <title>Vue</title>
</head>

<body>
    <div id="app">
        <button type="button" @click="click">
            <span v-if="fileName">重新上傳</span>
            <span v-else>上傳檔案</span>
        </button>
        <span>{{fileName}}</span>
        <input type="file" ref="uploadFile" style="display:none" accept="image/gif, image/jpeg" @change="upload"/>
    </div>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                fileName: ''
            },
            methods: {
                click () {
                    // 偷樑換柱,觸發檔案上傳
                    this.$refs.uploadFile.click();
                },
                upload (event) {
                    let files = event.target.files || event.dataTransfer.files;

                    if (!files.length) {
                        this.fileName = '';
                        return;
                    }
                    this.fileName = files[0].name;

                    // 上傳之後呼叫介面...
                    let params = new FormData();
                    params.append('file', files[0]);
                    console.log(params);

                    this.$refs.uploadFile.value = null; // 移除檔案,可以保證上傳同樣的檔案時,也會觸發change事件
                }
            }
        })
    </script>
</body>

</html>
複製程式碼

感想

遇到問題的時候多去看看別人是怎麼寫的,借鑑一下,解決問題的同時能夠學習很多東西。

相關文章