前言:很多项目中都需要用到图片上传功能,而其多处使用的要求,为了避免重复造轮子,让我决定花费一些时间去深入了解,最终封装了一个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. php5.6安装gd库

    rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm rpm -Uvh ht ...

  2. enum 枚举类型默认值

    enum value { one, two, three, four }; 默认值

  3. 【cocos2d-x 3.5】Lua动画API

    1.加载动画 local node = cc.CSLoader:createNode("ActionTimeline/DemoPlayer_skeleton.csb") local ...

  4. Ubuntu16.04 下创建新用户并赋予sudo权限

    https://blog.csdn.net/wales_2015/article/details/79643336

  5. [转]Birdfont 2.10 发布,字体编辑器

    最近在忙大数据.黑天鹅算法实盘测试 许久没有更新字库方面的资料,汗一个... 今天转一个 :Birdfont 2.10 发布,字体编辑器 字体编辑器,向来很少,除了fontlab的几个昂贵的商业版,就 ...

  6. KALI视频学习31-35

    (三十一)Kali漏洞利用之SET Social Enginnering Toolkit(SET)是一个开源.Python驱动的社会工程学渗透测试工具,提供了非常丰富的攻击向量库.是开源的社会工程学套 ...

  7. What's the difference between SDK and Runtime in .NET Core?

    What's the difference between SDK and Runtime in .NET Core? Answer1 According to the .Net Core Guide ...

  8. apm的学习资料

    百度搜索    apm博客园 实现自己的APM http://www.cnblogs.com/Kevin-moon/archive/2009/02/23/1395039.html 异步机制,一共5篇文 ...

  9. python 执行字符串中的python代码

    mycode = 'print("hello world")' code = """ def mutiply(x,y): return x*y pri ...

  10. 《Blue Flke团队》第二次作业通讯录项目开题报告

      Just_Do_IT! N:8A:8B:7C:6D:8总分:37   Miracle-House N:8A:6B:7C:6D:8总分:35   Spring_Four N:7A:7B:8C:8D: ...