一、webkitdirectory
撸代码之前还是先了解一下 input 标签的【webkitdirectory】属性,今天也是主要依赖 这个属性来帮助我们实现需求!
A Boolean indicating whether or not to only allow the user to choose a directory (or directories, if multiple is also present)
一个布尔值,指示是否只允许用户选择一个目录(如果同时存在多个目录,则为一个或多个目录)
这是 MDN 上对 【 webkitdirectory 】属性的解释。一句话,非常通透!
这段话就不做翻译了,大概我们可以看出来,【webkitdirectory 】属性的兼容性不是特别好,所以对【ie6,ie7.....】兼容的小伙伴要慎用....
二、具体实现
因为用的是 【Vue2.0】的技术栈,所以演示就直接用 Vue 来做演示了!
1. Template 设计
唯一的注意点就是:这里通过【v-show 隐藏 DOM 节点,然后用 ref 获得节点去调用原生 input 的方法】,然后通过 input change 是获取的 e.target 去进行解析;
<template> <div class="receive-img"> <input v-show="false" type="file" ref="inputFile" accept="image/*" webkitdirectory @change="receiveImg" /> <div class="btn"> <button @click="chooseImgList">点击选择文件夹</button> </div> <div class="image-list-container"> <div v-for="item in imageList" :key="item.imgUrl"> <div class="image-list-item"> <el-image fit="cover" :src="item.imgUrl"></el-image> </div> <div class="image-list-text"> <div>{{ item.imgName }}</div> <div>{{ item.size + "KB" }}</div> </div> </div> </div> </div> </template> <style lang="scss"> .receive-img { width: 100%; height: 100%; .btn { margin: 100px auto 0 auto; } .image-list-container { width: 100%; height: 250px; display: flex; align-items: flex-start; justify-content: flex-start; border: 1px solid #d2d2d2; padding: 0 10px; .image-list-item { width: 210px; height: 210px; margin-left: 15px; text-align: center; } .image-list-text { width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; } .image-list-item:hover { cursor: pointer; } } } </style>
2. JavaScript 执行
通过 【 FileReader 】去读取文件的 进而读取出图片的name/path/size ;不过需要注意这里需要手动调用 【API】上传图片,演示的图片是 base64
import uploadFormData from "@/utils/uploadFormData.js" <script> export default { name: "ReceiveImage", data() { return { imageList: [], }; }, methods: { chooseImgList() { if (this.imageList.length == 0) { this.$refs["inputFile"].click(); } }, receiveImage (e) { var fmDataList = []; var count = e.target.files.length; for (let item in e.target.files) { let reader = new FileReader(); const file = e.target.files[item]; if (typeof file == 'object' && (file.name.indexOf('jpg') > -1 || file.name.indexOf('png') || file.name.indexOf('jpeg'))) { reader.readAsDataURL(e.target.files[item]); reader.onloadend = (e) => { // 这里的e.target就是reader let base64 = e.target.result; fmDataList.push({ file: base64, fileName: file.name }) this.imageList.push({ imgName: file.name, size: Math.ceil(file.size / 1000) }) count--; if (count == 0) { uploadFormData(fmDataList).then(result => { if (result.fileNames) { this.imageList.forEach((t, index) => { t['fileName'] = result.fileNames[index] }) } this.imageListStatus = true; }) } } } } }, }, }; </script>
3. 原生方式实现上传
值得介绍的是上述代码中的封装好的 uploadFormData 方法,因为我们用原生的方式去上传,且上传的是一个二进制流的 formData ,所以我们就不能再用项目里面已经封装好的 request 去发起请求,而是要用 new XMLHttpRequest(),具体怎么实现,可以看下面实现步骤( 当然具体要看后端 API 怎么去做),以下面为例:
封装 uploadFormData.js
/** * @param {string} file base64格式的图片 * @param {string} imgFormat 需要转化为 formData 的图片格式 */ var uploadImgUrl = process.env.VUE_APP_BASE_API + "/common/upload"; // 上传的图片服务器地址 import data2blob from "@/lib/data2blob.js"; import mimes from "@/lib/mimes.js"; import { getToken } from "@/utils/auth"; export default function (files, imgFormat = 'png') { // files 就是上面 fmDataList 里的 base64 数组 const allowImgFormat = ["jpg", "png"]; const format = allowImgFormat.indexOf(imgFormat) > -1 ? 'jpg' : imgFormat; const fmData = new FormData(); if (Array.isArray(files) && files.length > 0) { files.forEach(t => // data2blob() 方法是通过 Blob 转化为二进制流 fmData.append('file', data2blob(t.file, mimes[format])) ) } else { fmData.append('file', data2blob(files, mimes[format])) } // XMLHttpRequest 去做具体请求 return new Promise((resolve, reject) => { let client = new XMLHttpRequest(); client.open("POST", uploadImgUrl, true); client.withCredentials = false; // 是否支持跨域 client.onreadystatechange = function () { if (this.readyState !== 4) { return; } if (this.status === 200 || this.status === 201) { resolve(JSON.parse(this.responseText)); } else { reject(this.status); } }; client.setRequestHeader("Authorization", "Bearer " + getToken()); client.send(fmData); }) }
base64 转 二进制 data2blob.js
/** * database64文件格式转换为2进制 * * @param {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了 * @param {[String]} mime [description] * @return {[blob]} [description] */ export default function(data, mime) { data = data.split(',')[1]; data = window.atob(data); var ia = new Uint8Array(data.length); for (var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); }; return new Blob([ia], { type: mime }); };
文件格式 mimes.js
export default { 'jpg': 'image/jpeg', 'png': 'image/png', 'gif': 'image/gif', 'svg': 'image/svg+xml', 'psd': 'image/photoshop' };
边记录边学习边成长,加油加油加油~~~~