前言:很多项目中都需要用到图片上传功能,而其多处使用的要求,为了避免重复造轮子,让我决定花费一些时间去深入了解,最终封装了一个vue的图片上传组件。现将总结再次,希望有帮助。

Layout

  <div class="upload-wraper">
   <input type="file" id="upload_ele" multiple="false" accept="image/*" @change="uploadFile()" />
</div>

type=file将类型设置为选择文件

multiple是否允许文件的多选

accept="image/*" 将文件的类型限制为image类型,*包括所有格式的图片

change事件当type设置为file后,出发的事件为change,也可通过submit实现

这里布局的话,因为是vue组件所以简单点,不需要多个input构成form表单,然后通过submit提交,一个input通过change事件来实现上传

Js

Basic information for uploading files

  let oFIle = document.getElementById('upload-ele').files[0];

files是input设置为file后的一个js内置对象。files对象死一个read-only属性,不可被修改!

打印出oFile后可以看到该文件对象的basic information.如下:

isClosed:false 是否已经结束,可以理解为标签是否闭合

lastModified:1539602132000最后更改的时间timeStamp

lastModifiedDate:Mon Oct 15 2018 19:15:32 GMT+0800 (CST) {}最后更改时间

name:"D9791645A5DF19D17FD7392A080E7A28.jpg"图片的名称

path:"/Users/mac/Documents/D9791645A5DF19D17FD7392A080E7A28.jpg"图片所在的路径为本地路径

Size:38938图片的大小信息 单位为kb

type:'image/jpeg'图片的类型

webkitRelativePath:""文件相关的路径

File Size Processing

大小判断

  (oFile.size / 1024) > 1024

1M = 1024KB

Smaller

 let form = new FormData();
form.append('file',oFile);
let xhr = new XMLHttpRequest();
xhr.open('post',url,true);
xhr.timeout = 30 * 1000;
xhr.upload.onprogress = this.progress;
xhr.onload = this.uploadComplete;
xhr.onerror = this.uploadFailed;
xhr.upload.onloadstart = () => {
let date = new Date().getTime();
let initSize = 0;
}
xhr.send(form);

XMLHttpRequest()是js内置对象,可以使用该属性实现请求头的处理操作。

xhr.open(); 请求方法: post,url: 服务器接受的地址,true/false 是否异步

xhr.timeout; 设置超时时间,据情况而定

xhr.ontimeout; 超时处理,一般为取消请求

xhr.upload.onprogress; 进程处理 ,上传文件的进度处理

xhr.onload; 请求成功处理

xhr.onerror; 请求失败处理

Xhr.upload.onloadstart; 请求开始处理的操作,一般创建时间戳,初始化大小。

xhr.send(); 请求配置完毕,发送请求

这里小于1M的文件是可以直接通过放到formData中,通过配置xhr将图片对象上传到oss,在请求成功时拿到图片的网络路径供后,提供给后端。

Larger

why:为什么要对大于1M的图片进行处理呢?因为文件在大于1M的一般是上传失败的。常见的ftp文件上传时,默认是2M,大于时,会上传失败,所以这里的图片上传进行了大于1M压缩的处理。

how:流程与小于1M时十分相似,不过,这里添加了图片的压缩处理。

more:一般在较大文件处理时,后端也是可以进行处理的,单独提供较大图片的接口。这时,我们就不需要进行压缩了,只需要在判断大于1024KB时接口更换为处理较大文件的接口即可。

如何压缩?

  1. 通过FileReader对象将文件对象读取成base64格式。

  2. 通过Image对象结合canvas画布将base格式的图片将一定的比例缩小后重新保存成为base64格式。

  3. 将base64格式转换成Blob流后,图片就可以说是压缩完成了。

  4. 剩下的步骤重复formData,XMLHttpRequest即可完成较大图片的上传。这里需要注意的是,在formData中防止文件时,因为此时是Blob流,所以防止文件时,需要自定义文件格式,这里的处理是 Blob文件 + 时间戳与.jpg组成。

组件源码

<template>
<!-- 图片上传组件 -->
<div class="upload-wraper">
<input type="file" id="upload-ele" multiple="false" accept="image/*" @change="uploadFile(url,quality,hasApi,BigUrl)">
<toast v-model="total.isShow" type="text">{{total.text}}</toast>
</div>
</template>
<script>
import { Indicator } from 'mint-ui';
import { Toast } from 'vux';
export default {
name: 'uploadImage',
components: {
Indicator,
Toast,
},
props: {
'url': String, //小与1M的api
'quality': Number, //图片质量
'BigUrl': {
type: String,
default: '',
}, //大于1M图片的api
'hasApi': {
type: Boolean,
default: false
} //是否对大于1M的图片单独分配接口
},
data() {
return {
total: {isShow:false,text:""}
}
},
methods: {
uploadFile(url,quality,hasApi,BigUrl) {
Indicator.open(`上传中`);
// files是input设置为file后的一个内置对象。files对象是一个只读属性,不可被修改。
var oFile = document.getElementById('upload-ele').files[];
console.log('File Object',oFile);
var form = new FormData();
// 大小判断 如果大于1M就新型压缩处理
// console.log('File Size Unit:KB',(oFile.size / 1024))
if((oFile.size / ) > ) {
if(hasApi) {
form.append('file',oFile);
let xhr = new XMLHttpRequest(); //XMLHttpRequest Object
xhr.open('post',BigUrl,true); // Method: post,url: server receive address,true/false isAsync
xhr.timeout = * ; //Timeout one minute;
xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
xhr.upload.onprogress = this.progress; //Progress Function
xhr.onload = this.uploadComplete; //Upload Success Function
xhr.onerror = this.uploadFailed; //Upload Failed Funciton
xhr.upload.onloadstart = () => {
let date = new Date().getTime(); // TimeStamp Prevents Caching
let initSize = ; // Init File Size Zero
} // Upload Start
xhr.send(form);
} else {
this.imgCompress(oFile,{quality: quality},
(base64Codes) => {
var bl = this.convertBase64UrlToBlob(base64Codes);
form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
console.log(form);
let xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
xhr.upload.onprogress = this.progress; //Progress Function
xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
xhr.onload = this.uploadComplete; //Upload Success Function
xhr.onerror = this.uploadFailed; //Upload Failed Funciton
xhr.upload.onloadstart = function() {
let ot = new Date().getTime(); // TimeStamp Prevents Caching
let oloaded = ; // Init File Size Zero
};// Upload Start
xhr.send(form);
})
}
} else {
// 小与1M
form.append('file',oFile);
let xhr = new XMLHttpRequest(); //XMLHttpRequest Object
xhr.open('post',url,true); // Method: post,url: server receive address,true/false isAsync
xhr.timeout = * ; //Timeout one minute;
xhr.ontimeout = this.uploadTimeout; // Upload Timeout Function
xhr.upload.onprogress = this.progress; //Progress Function
xhr.onload = this.uploadComplete; //Upload Success Function
xhr.onerror = this.uploadFailed; //Upload Failed Funciton
xhr.upload.onloadstart = () => {
let date = new Date().getTime(); // TimeStamp Prevents Caching
let initSize = ; // Init File Size Zero
} // Upload Start
xhr.send(form);
}
},
/**
* @description Request Success
*/
uploadComplete(evt) {
let res = JSON.parse(evt.target.responseText);
if(evt.target.readyState == && evt.target.status == ) {
this.$emit('upload',res.result.url);
} else {
this.uploadFailed();
}
},
/**
* @description Request Failed
*/
uploadFailed(evt) {
Indicator.close();
this.total = {
isShow:true,
text:"上传失败"
}
},
/**
* @description Timeout Function
*/
uploadTimeout(evt) {
this.cancleUploadFile(evt)
Indicator.close();
this.total = {
isShow:true,
text:"请求超时"
}
},
/**e
* @description Upload Cancel
*/
cancleUploadFile(evt) {
evt.abort();
},
/**
* @description Requst Loading....
*/
progress(progressEvent) {
if(!progressEvent.lengthComputable) {
this.total = {
isShow:true,
text:"进度读取失败"
}
return false;
}
let precent = Math.floor( * progressEvent.loaded / progressEvent.total); //Upload Progress
if(precent < ) {
Indicator.open(`上传中${precent}%`);
} else {
Indicator.close();
this.total = {
isShow:true,
text:"上传成功"
}
}
},
/**
* @description 图片压缩
* @param {Object} file 压缩的文件
* @param {Number} width 压缩后端宽度,宽度越小,字节越小
*/
imgCompress(file,width,callBack) {
var ready = new FileReader();
ready.readAsDataURL(file);
ready.onload = () => {
this.canvasDataURL(ready.result,width,callBack);
}
},
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
convertBase64UrlToBlob(urlData) {
var arr = urlData.split(","),
mime = arr[].match(/:(.*?);/)[],
bstr = atob(arr[]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
/**
* @description 大于1M的图片进行重新绘制压缩
*/
canvasDataURL(path, obj, callback) {
var img = new Image();
img.src = path;
img.onload = () => {
// var that = this;
// 默认按比例压缩
var w = this.width,
h = this.height,
scale = w / h;
w = obj.width || w;
h = obj.height || w / scale;
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(img, , , w, h);
// 图像质量
if (obj.quality && obj.quality <= && obj.quality > ) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL("image/jpeg", quality);
// 回调函数返回base64的值
callback(base64);
};
},
}
}
</script>
<style lang="less" scoped>
.upload-wraper {
width: %;
height: %;
}
</style>
这里是公众号项目,所以,这里引入的第三方插件为mint-ui和vux。具体情况视情况而定。

该组件例外封装了,后端是够对较大图片的处理,如果后端已经进行处理,则直接调用。如果没有处理,则进行压缩处理,

组件的封装,可灵活修改,还有很多地方仍待修改

插槽,图片上传后,回显可在组件内部实现。借由slot更加完美。

该组件限制了图片文件的上传,其他文件则不行。

引入如下:

 <upload-image class="upload" :quality='.7' :url="$base.uploadUrl" :hasApi="false" @upload='uploadImage'></upload-image>

参考文献

  1. js内置file(文件)对象。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

  2. FormData对象的。https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData

  3. XMLHttpRequest对象。https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

  4. Image对象。https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image

  5. Canvas画布。内容较多,建议通过学习视频了解。在本文中主要用于大型图片的压缩处理

  6. base64和Blob的转换,百度很多已经封装好的。可直接使用。eg:https://www.cnblogs.com/jiujiaoyangkang/p/9396043.html


Data: 2018-12-13

author: Csun

vue图片上传组件的更多相关文章

  1. AntDesign VUE:上传组件图片/视频宽高、文件大小、image/video/pdf文件类型等限制(Promise、Boolean)

    文件大小限制 - Promise checkFileSize(file, rules) { return new Promise((resolve, reject) => { file.size ...

  2. AntDesign VUE:上传组件自定义限制的两种方式(Boolean、Promise)

    AntD上传组件 AntDesign VUE文档 第一种方式 beforeUpload(file) { let isLt = true if (filesSize) { isLt = file.siz ...

  3. Jquery图片上传组件,支持多文件上传

    Jquery图片上传组件,支持多文件上传http://www.jq22.com/jquery-info230jQuery File Upload 是一个Jquery图片上传组件,支持多文件上传.取消. ...

  4. H5拍照、选择图片上传组件核心

    背景 前段时间项目重构,改成SSR的项目,但之前用的图片选择上传组件不支持SSR(server-side-render).遂进行了调研,发现很多的工具.但有的太大,有的使用麻烦,有的不满足使用需求.决 ...

  5. 微信小程序简单封装图片上传组件

    微信小程序简单封装图片上传组件 希望自己 "day day up" -----小陶 我从哪里来 在写小程序的时候需要上传图片,个人觉得官方提供的 Uploader 组件不是太好用, ...

  6. 基于Node的React图片上传组件实现

    写在前面 红旗不倒,誓把JavaScript进行到底!今天介绍我的开源项目 Royal 里的图片上传组件的前后端实现原理(React + Node),花了一些时间,希望对你有所帮助. 前端实现 遵循R ...

  7. 分享一个react 图片上传组件 支持OSS 七牛云

    react-uplod-img 是一个基于 React antd组件的图片上传组件 支持oss qiniu等服务端自定义获取签名,批量上传, 预览, 删除, 排序等功能 需要 react 版本大于 v ...

  8. vue图片上传的简单组件

    <template> <div class="rili" id="rili"> <div class="updel&qu ...

  9. vue 图片上传

    功能说明: 1.调用手机拍照功能 2.调用相册功能 3.图片上传功能 4.图片预览功能 5.图片删除功能 关键点: .input 新增multiple .accept="image/*处理I ...

随机推荐

  1. Singapore retailer will release this adidas NMD R1

    Select spots are restocking the adidas NMD Singapore this Friday, Feb 24th featuring three different ...

  2. 【UI】android如何绘制一个饼图

    代码下载 需求 1:实心饼图,颜色填充百分比区域 2:带区域说明 3:饼图有阴影 思路:这个其实和绘制进度条原理差不多,都是360度根据所占百分比算出绘制弧度,然后调用canvas的画弧函数. 阴影其 ...

  3. fileupload上传文件时带参数

    var userID = ""; $('#picture').fileupload({ url: "http://localhost:35708/Handler/File ...

  4. pyDay14

    内容来自廖雪峰的官方网站. 1.map的优点:省代码 + 提高可读性. 2.map 运用示例: >>> def f(x): ... return x * x ... >> ...

  5. Ubuntu 14.04 下安装 TFTP 艰辛之路【转】

    本文转载自:https://blog.csdn.net/donglicaiju76152/article/details/76651210 背景 按说在Linux下安装tftp server 很简单, ...

  6. try catch finally return

    public override bool Start(IServerConfig config) { bool flag = true; listenSocket = new Socket(Liste ...

  7. BloomFilter–大规模数据处理利器

    转自: http://www.dbafree.net/?p=36 BloomFilter–大规模数据处理利器 Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法. ...

  8. SQL 触发器的缺点 坏处 弊端 哼╭(╯^╰)╮

    (自己总结,有误请不吝赐教) 1.如果触发频率高,占用内存,降低数据访问速度 2.相对不灵活,一旦触发马上执行,不能排除特殊情况 3.一定程度上打乱代码结构,相关的代码都需要特别注释,否则造成阅读和维 ...

  9. CSS 再学习,文本处理

    文本缩进(对p,div有效:对span无效) p {text-indent: 5em;} Tips:一般来说,可以为所有块级元素应用 text-indent,但无法将该属性应用于行内元素(span), ...

  10. 树状数组 Binary Indexed Tree/Fenwick Tree

    2018-03-25 17:29:29 树状数组是一个比较小众的数据结构,主要应用领域是快速的对mutable array进行区间求和. 对于一般的一维情况下的区间和问题,一般有以下两种解法: 1)D ...