从零实现Vue的组件库(四)- File-Reader实现

栏目: JavaScript · 发布时间: 5年前

内容简介:实现一个File-Reader组件用来读取本地资源。概述: 在用户手动上传一些资源的时候,需要分为两步,第一步是将其从本地读取出来,得到一个代码

实现一个File-Reader组件用来读取本地资源。

概述: 在用户手动上传一些资源的时候,需要分为两步,第一步是将其从本地读取出来,得到一个 file 对象,然后再上传至服务器。该组件用于第一步,然后可通过后续进一步封装程Upload组件。

该组件的痛点在于:
preventDefault

1. 实例

从零实现Vue的组件库(四)- File-Reader实现

代码

<!-- 基础用法 -->
<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 对象中,读取选中待上传的文件对象

从零实现Vue的组件库(四)- File-Reader实现

包含着 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 ReaderreadAsDataURL ,由于该方法是异步的,所以将其封装为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监听 dragenterdragoverdrop 事件。

<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" />acceptmultiple 等属性,利用 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)   
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

面向对象技术UML教程

面向对象技术UML教程

王少峰 / 清华大学出版社 / 2004-2 / 24.00元

《面向对象技术UML教程》主要介绍统一建模语言UML及其应用。全书内容丰富,包括UML的用例图、顺序图、协作图、类图、对象图、状态图、活动图、构件图和部署图等9个图中所涉及的术语、规则和应用,以及数据建模、OCL、业务建模、Web建模、设计模式、OO实现语言、RUP等方面的内容,同时介绍了Rose开发工具中的一些用法。《面向对象技术UML教程》最后是一个课程注册系统的实例研究,以及一些思考题和设计......一起来看看 《面向对象技术UML教程》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具