vue框架下:label+input选择文件上传文件(踩坑)

    科技2022-07-31  105

    文章目录

    目的问题问题代码原因分析解决方案写在最后

    目的

    使用Vue框架和axios上传文件: label+input选择文件上传文件,将input标签隐藏,只显示label标签,同时在事件函数里面通过改变Vue data的数据实现显示标签的变化


    HTML代码: <template> <div class="page"> <div class="upload-mod-wrap"> <!-- 上传文件的盒子 --> <div class="upload-file"> <div class="upload-file-header"> <a href="javascript:;">X</a> </div> <div ref="uploadFileBody" class="upload-file-body"> <!-- 上传文件input --> <div v-show="isActive == 0" class="upload-file-btn"> <div class="input-label" @click="clickInput"> <span>+</span><br /> <span>选取文件</span> </div> <input ref="fileInput" type="file" id="js-upload-file" @change="uploadFile" /> </div> <!-- 进度条 --> <div v-show="isActive == 1" class="upload-file-loading clear"> <div class="loading-bar"> <div ref="loadingBar" id="londing" :style="{ width: progress }"> <span v-if="!isLoading">上传完成</span> </div> </div> <div class="loading-info"> <span>文件名:</span> <span class="echo-size"> {{ filename }}</span> <br /> <span>进度:</span> <span class="echo-size"> {{ progress }}</span> </div> </div> <!-- 上传文件的表面 --> <!-- <div class="upload-file-face">+</div> --> </div> <div class="upload-file-tail"> <div> <button>取消</button> <button>退出</button> </div> </div> </div> </div> <div class="page-content"></div> </div> </template>

    修改后的JS代码:

    <script> const axios = require("axios"); export default { name: "OPenFile", data() { return { isActive: 0, isLoading: true, errInfo: "", filename: "还未选择任何文件", progress: "0%", }; }, methods: { clickInput() { this.$refs.fileInput.click(); }, uploadFile() { const fileInput = this.$refs.fileInput, oFile = fileInput.files[0], filesize = oFile.size; this.filename = oFile.name; console.log(typeof this.filename); if (oFile > 1) { this.errInfo = "一次只能上传一个文件"; alert(this.errInfo); return; } if (filesize > 1048576000) { this.errInfo = "最大上传文件大小为10M"; alert(this.errInfo); return; } this.doUpload(oFile); }, doUpload(file) { if (file) { const form = new FormData(), loadBar = this.$refs.loadingBar; this.isActive = 1; form.append("file", file); axios.post("http://127.0.0.1:8888/api/UploadFile", form, { headers: { "content-type": "multipart/form-data" }, onUploadProgress: (progressEvent) => { this.progress = (((progressEvent.loaded / progressEvent.total) * 100) | 0) + "%"; if (this.progress === "100%") { this.isLoading = false; } }, }).then((response) => { console.log(response.data); }); } }, }, }; </script>

    问题

    在事件函数里面改变data中是数据时页面并不会渲染,但是事件触发且通过console.log可以输出改变后数据。

    问题代码

    问题都是在改变data中的数据

    uploadFile() { const fileInput = this.$refs.fileInput, oFile = fileInput.files[0], filesize = oFile.size; //这里是问题,能够在下个console.log输出改变后的this.filename,但是实际上却没有改变 this.filename = oFile.name; console.log(this.filename) this.doUpload(oFile); }, doUpload(file) { if (file) { const form = new FormData(), loadBar = this.$refs.loadingBar; //这里是问题 this.isActive = 1; form.append("file", file); ... }

    原因分析

    通过排除问题出现在label和input两个之间

    开始我是这样写的,这样写上传文件一点问题没有,文件可是上传当服务端,然后在我要修改js中的data里面的数据时问题就来了。

    <div v-show="isActive == 0" class="upload-file-btn"> <label class="input-label" for="js-upload-file"> <span>+</span><br /> <span>选取文件</span> </div> <input ref="fileInput" type="file" id="js-upload-file" @change="uploadFile" /> </div>

    虽然这样这控制太中能够输出改变后的值,但是我通过Vue devtools查看数据,却发现数据并没有发生改变。

    对于这个问题,实际上我并不是想的很明白,事件确实是触发了,同时异步文件上传也成功了。通过点击label也确实聚焦到了input上。但是加上vue 修改data却不会发现改变。我无语了

    解决方案

    最后解决,将label改成div加上点击事件监听,通过事件函数将点击input选择文件: HTML: <div v-show="isActive == 0" class="upload-file-btn"> <div class="input-label" @click="clickInput"> <span>+</span><br /> <span>选取文件</span> </div> <input ref="fileInput" type="file" id="js-upload-file" @change="uploadFile" /> </div>

    JS:

    clickInput() { //点击input this.$refs.fileInput.click(); },

    写在最后

    不排除因为环境的影响,可能只是个个例。 效果图片:

    保存一下代码:

    <template> <div class="page"> <div class="upload-mod-wrap"> <!-- 上传文件的盒子 --> <div class="upload-file"> <div class="upload-file-header"> <a href="javascript:;">X</a> </div> <div ref="uploadFileBody" class="upload-file-body"> <!-- 上传文件input --> <div v-show="isActive == 0" class="upload-file-btn"> <div class="input-label" @click="clickInput"> <span>+</span><br /> <span>选取文件</span> </div> <input ref="fileInput" type="file" id="js-upload-file" @change="uploadFile" /> </div> <!-- 进度条 --> <div v-show="isActive == 1" class="upload-file-loading clear"> <div class="loading-bar"> <div ref="loadingBar" id="londing" :style="{ width: progress }"> <span v-if="!isLoading">上传完成</span> </div> </div> <!-- 完成后显示信息 --> <!-- <div v-else class="loaded">上传完成</div> --> <div class="loading-info"> <span>文件名:</span> <span class="echo-size"> {{ filename }}</span> <br /> <span>进度:</span> <span class="echo-size"> {{ progress }}</span> </div> </div> <!-- 上传文件的表面 --> <!-- <div class="upload-file-face">+</div> --> </div> <div class="upload-file-tail"> <div> <button>取消</button> <button>退出</button> </div> </div> </div> </div> <div class="page-content"></div> </div> </template> <script> const axios = require("axios"); export default { name: "OPenFile", data() { return { isActive: 0, isLoading: true, errInfo: "", filename: "还未选择任何文件", progress: "0%", }; }, methods: { clickInput() { this.$refs.fileInput.click(); }, uploadFile() { const fileInput = this.$refs.fileInput, oFile = fileInput.files[0], filesize = oFile.size; this.filename = oFile.name; console.log(typeof this.filename); if (oFile > 1) { this.errInfo = "一次只能上传一个文件"; alert(this.errInfo); return; } if (filesize > 1048576000) { this.errInfo = "最大上传文件大小为10M"; alert(this.errInfo); return; } // if (!/\.(doc|docx|txt)$/.test(this.filename)) { // this.errInfo = "你上传的文件格式不是doc|docx|txt中的一种"; // return; // } this.doUpload(oFile); }, doUpload(file) { if (file) { /* let fd = new FormData(); const filename = file.name; fd.append("file", file); axios({ method: "post", url: "http://127.0.0.1:8888/api/UploadFile", headers: { "content-type": "multipart/form-data", }, data: { fd, }, }).then((response) => { console.log(response.data); }); */ const form = new FormData(), loadBar = this.$refs.loadingBar; this.isActive = 1; form.append("file", file); // form.append("my_buffer", new Buffer(10)); // form.append("my_file", fs.createReadStream("/foo/bar.jpg")); axios .post("http://127.0.0.1:8888/api/UploadFile", form, { headers: { "content-type": "multipart/form-data" }, onUploadProgress: (progressEvent) => { this.progress = (((progressEvent.loaded / progressEvent.total) * 100) | 0) + "%"; if (this.progress === "100%") { this.isLoading = false; } }, }) .then((response) => { console.log(response.data); }); } }, }, }; </script> <style lang='less' scoped> a { text-decoration: none; } .page { margin: 5px auto; width: 100%; background-color: rgb(196, 194, 194); overflow: hidden; } .upload-mod-wrap { position: fixed; top: 75px; left: 0; margin: 0; padding: 0; width: 100%; height: 100%; background-color: rgba(99, 99, 99, 0.5); .upload-file { position: absolute; top: 50%; left: 50%; margin: -200px 0 0 -250px; width: 500px; height: 300px; background-color: #fff; .upload-file-header { position: relative; width: 100%; height: 30px; line-height: 30px; background-color: rgb(86, 193, 240); a { color: #fff !important; position: absolute; top: 2px; right: 7px; } } .upload-file-body { position: relative; width: 100%; height: 200px; margin-top: 5px; overflow: hidden; .upload-file-btn, .upload-file-loading { margin: 40px auto; width: 300px; height: 120px; border-radius: 5px; } .upload-file-btn { border: 2px dashed rgba(99, 99, 99, 0.5); input { display: none; } .input-label { display: inline-block; cursor: pointer; box-sizing: border-box; padding-top: 30px; text-align: center; width: 300px; height: 120px; color: rgb(191, 178, 178); :first-child { font-size: 80px; } } } .upload-file-loading { box-sizing: border-box; border: 3px solid rgba(75, 174, 224, 0.5); padding: 10px 0; position: relative; .loading-bar { width: 240px; height: 30px; box-sizing: content-box; border-radius: 30px; border: solid 2px rebeccapurple; margin: 0 auto; padding: 2px; overflow: hidden; text-align: center; #londing { height: 30px; width: 33%; // margin: 1px; border-radius: 30px; background-color: rgb(86, 193, 240); } span { height: 30px; width: 240px; line-height: 32px; font-size: 20px; font-weight: bolder; } } .loading-info { position: absolute; width: 240px; height: 70px; line-height: 1px; left: 50%; margin-left: -120px; padding: 5px 10px; font-size: 16px; span { display: inline-block; overflow: hidden; line-height: 25px; } .echo-size { line-height: 25px; font-size: 13px; width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } } .loaded { width: 240px; height: 30px; background-color: rgb(86, 193, 240); color: rgb(17, 35, 21); font-size: 20px; line-height: 30px; text-align: center; margin: 15px auto 0; } } } .upload-file-tail { position: relative; width: 100%; height: 30px; right: 10px; div { position: absolute; top: 2px; right: 7px; button { margin: 10px; } } } } } .page-content { margin: 6px auto; width: 1000px; height: 600px; background-color: rgb(255, 255, 255); } .clear::after .clear::before { content: ""; display: block; clear: both; } </style>
    Processed: 0.013, SQL: 9