从零实现Vue的组件库(四)- File-Reader实现
栏目: JavaScript · 发布时间: 5年前
内容简介:实现一个File-Reader组件用来读取本地资源。概述: 在用户手动上传一些资源的时候,需要分为两步,第一步是将其从本地读取出来,得到一个代码
实现一个File-Reader组件用来读取本地资源。
概述: 在用户手动上传一些资源的时候,需要分为两步,第一步是将其从本地读取出来,得到一个 file
对象,然后再上传至服务器。该组件用于第一步,然后可通过后续进一步封装程Upload组件。
preventDefault
1. 实例
代码
<!-- 基础用法 --> <fat-filereader accept=".png, .jpg" :size="500 * 1024" @success="event => readHandler(event, 'file')" @error="errorHandler" /> <!-- 自定义上传区域 --> <fat-filereader @success="event => readHandler(event, 'otherFile')"> <div slot="clickarea" class="upload-area"> <fat-icon class="icon" name="cloud_upload" size="24"/> </div> </fat-filereader> <!-- 拖拽上传 --> <fat-filereader dragable @success="event => readHandler(event, 'anotherFile')"> <div slot="clickarea" class="upload-area"> <fat-icon class="icon" name="cloud_upload" size="24"/> </div> <span v-if="anotherFile.name">已上传:{{ anotherFile.name }}</span> </fat-filereader> <!-- 上传多个文件 --> <fat-filereader multiple :limit="5" @success="multipleHandler" @error="errorHandler"/> 复制代码
实例地址:File-Reader 实例
代码地址: Github UI-Library
2. 原理
该组件的实现是基于原生的 <input type="file" />
,再通过添加拖拽功能来以达到上图效果。
组件的基本结构如下,主要包含两个部分:
<slot name="clickarea"></slot> < input type="file" />
<div :class="['file-reader', { 'is-disabled': disabled }]" > <div class="click-area" @click.stop="eventHandler('readFile')" @dragenter="prevent" @dragover="prevent" @drop="event => dragable && eventHandler('dropReadFile', event)" > <slot name="clickarea"> <fat-button :disabled="disabled" type="success">上传</fat-button> </slot> </div> <slot></slot> <input ref="input" type="file" class="is-hide" v-bind="$attrs" @change="event => eventHandler('change', event)" :disabled="disabled" > </div> </template> 复制代码
在 <slot name="clickarea"></slot>
外层包裹 div
标签,用于监听该区域的点击事件。当它触发时,相关处理函数为
const handler = { readFile: () => { // fix change again this.$refs.input.value = ""; this.$refs.input.click(); }, ... }; 复制代码
先重置 this.$refs.input.value
,不然会出现无法再上传的问题。然后,触发原生 <input type="file" />
的点击事件,此时页面上会弹出原生的上传框。
监听该标签的 change
事件, @change="event => eventHandler('change', event)
,如果发生上传,会触发相关处理函数。
eventHandler(type, event = {}) { const handler = { ... // read files change: event => (this.sourceFiles = event.target.files) }; handler[type] && handler[type](event); } 复制代码
从 event
对象中,读取选中待上传的文件对象
包含着 name
文件名, size
大小, type
类型等属性。
由于部分文件需要进行预览,例如img、svg等,所以需要生成对应的URL,基本方法为:
-
window.URL.createObjectURL
:该方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL; -
new FileReader
:该对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,再通过readAsDataURL
读取指定的 Blob 或 File 对象。
首先判断当前是否支持 window.URL && window.URL.createObjectURL
,如果支持,只需将已上传的 targetFiles
进行处理
Array.prototype.map.call(value, file => ({ // file => url url: window.URL.createObjectURL(file), file })); 复制代码
如果不支持该方法,则需要利用 File Reader
的 readAsDataURL
,由于该方法是异步的,所以将其封装为Promise形式
const getReader = file => { return new Promise(function(resolve, reject) { const fileReader = new FileReader(); // 读取相关文件 fileReader.readAsDataURL(file); // fileReader onload 时,返回其结果 fileReader.onload = () => resolve(fileReader.result); fileReader.onerror = () => fileReader.abort(); }); }; const readers = Array.prototype.map.call(value, file => getReader(file)); 复制代码
再利用 Promise.all
统一进行处理,结合已上传的 targetFiles
生成返回结果。
Promise.all(readers).then(results => { this.targetFiles = results.map((url, i) => ({ url, file: value[i] })); }); 复制代码
以上完成基本的上传、预览功能。然后添加拖拽上传功能,在clickArea监听 dragenter
、 dragover
、 drop
事件。
<div class="click-area" @click.stop="eventHandler('readFile')" @dragenter="prevent" @dragover="prevent" @drop="event => dragable && eventHandler('dropReadFile', event)" > <slot name="clickarea"> <fat-button :disabled="disabled" type="success">上传</fat-button> </slot> </div> 复制代码
相关处理函数为
eventHandler(type, event = {}) { const handler = { ... dropReadFile: event => { event.preventDefault(); this.sourceFiles = event.dataTransfer.files; } }; handler[type] && handler[type](event); }, prevent(event) { event.preventDefault(); } 复制代码
利用 event.dataTransfer.files
获取相关上传文件,再通过 event.preventDefault
阻止游览器的一些默认行为,例如直接预览该文件等。获取到 sourceFiles
之后的操作等同于之前点击上传。
读取完成之后需要对文件进行校验,主要有上传文件的大小以及数量,相关代码如下
targetFiles(value) { const { size, limit } = this; if (value.length > limit) { this.$emit("error", { msg: "the quantity of files is too large its number cannot exceed" }); } else { if ( value.some(item => { const { file: { size: fileSize } } = item; return size && fileSize > size; }) ) { this.$emit("error", { msg: "file is too large its size cannot exceed" }); } else { this.$emit("success", value); } } } } 复制代码
3. 使用
相关的原生 <input type="file" />
的 accept
, multiple
等属性,利用 v-bind=$attrs
传递给原生的 <input type="file" />
。
之后, 可以结合相关上传方法将其封装程Upload组件,以Axios为例
uploadFile (fileData) { const config = { // 依据当前环境配置 baseURL: ..., headers: { 'Content-type': 'multipart/form-data' } } let data = new FormData(); data.append('file', fileData); data.append('name', fileData.name); return Axios.post('upload url', data, config) } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 从零实现Vue的组件库(二)-Slider组件实现
- Vue自定义组件(简单实现一个自定义组件)
- 实现一个沙漏⏳组件
- angular 实现下拉列表组件
- 从零实现Vue的组件库(五)- Breadcrumb 实现
- 从零实现Vue的组件库(十)- Select 实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
面向对象技术UML教程
王少峰 / 清华大学出版社 / 2004-2 / 24.00元
《面向对象技术UML教程》主要介绍统一建模语言UML及其应用。全书内容丰富,包括UML的用例图、顺序图、协作图、类图、对象图、状态图、活动图、构件图和部署图等9个图中所涉及的术语、规则和应用,以及数据建模、OCL、业务建模、Web建模、设计模式、OO实现语言、RUP等方面的内容,同时介绍了Rose开发工具中的一些用法。《面向对象技术UML教程》最后是一个课程注册系统的实例研究,以及一些思考题和设计......一起来看看 《面向对象技术UML教程》 这本书的介绍吧!