vue+element-ui中的图片获取与上传
vue+element-ui中的图片获取与上传
工作上接触了一下图片的处理,图片的格式是文件流, 记录如下。
请求图片
请求图片的时候,带上{ responsetype: 'blob' }
, 否则图片显示的可能是乱码。
axios .post(url, parmas, { responsetype: 'blob' }) .then(res => { return promise.resolve(res); }) .catch(e => { return promise.reject(e); });
显示图片
图片返回的是文件流的形式, 控制台中显示的是乱码。
直接显示二进制图片会出错,所以我们要进行处理。
<!-- template中 --> <img alt="logo" :src="imageurl" @error="handleloaderror" />
/*------ script中------*/ let urlcreator = window.url || window.webkiturl; let imageurl = urlcreator.createobjecturl(res); this.imageurl = imageurl;
显示图片中,要对万一图片显示不出来的情况进行处理。使用onerror
事件可以对加载图片失败的情况进行处理。
handleloaderror(e) { const img = e.srcelement; this.imageurl = this.errorloadimg; // 用加载失败的图片替代之 img.onerror = null; // 清除错误:如果错误时加载时显示的图片出错,将会一直循环,所以我们必须清除掉错误,限制运行一次 }
上传图片:使用 element-ui 的 el-upload
自动上传,一次传一张图片
<el-upload action="uploadurl" :show-file-list="false" :accept="'image/*'" :headers="{token:$cookiestorage.token}" :on-success="handlesuccess" :on-error="handleerror" :before-upload="handlebeforeupload" :on-progress="handleprogress" > <el-button type="primary" size="medium">上传图片</el-button> </el-upload> <!-- action: 图片上传的地址 show-file-list: 是否显示文件上传列表 accept: 可接受的上传类型,image/*为图片 headers: 头部信息 on-success: 上传成功事件 on-error: 上传失败事件 before-upload: 上传前处理事件,返回一个值,值为false将阻止上传 on-progress: 上传中事件 -->
/*----- 以下为常用处理代码 ------*/ handlesuccess(response, file, filelist) { this.$success("上传成功"); }, handleerror() { this.$error("上传失败,请重新上传图片!"); }, handlebeforeupload(file) { const isimage = file.type.includes("image"); if (!isimage) { this.$message.error("上传文件类型必须是图片!"); } const islt2m = file.size / 1024 / 1024 < 2; if (!islt2m) { this.$message.error("上传图片大小不能超过 2mb!"); } return isimage && islt2m; }, handleprogress(event, file, filelist) { this.loading = true; // 上传时执行loading事件 }
手动上传,一次提交多个 el-upload 的图片
要求:每个 picture area 限制选择一张图片,点击确定后一起提交。
<el-upload action="myurl" :on-change="(file,filelist)=>{handlechange(file,filelist,1)}" :on-remove="(file,filelist)=>{handleremove(file,filelist,1)}" :auto-upload="false" :file-list="filelist[0]" ref="file1" > <el-button size="small">选择图片</el-button> </el-upload> <el-upload action="myurl" :on-change="(file,filelist)=>{handlechange(file,filelist,2)}" :on-remove="(file,filelist)=>{handleremove(file,filelist,2)}" :auto-upload="false" :file-list="filelist[1]" ref="file2" > <el-button size="small">选择图片</el-button> </el-upload> <el-upload action="myurl" :on-change="(file,filelist)=>{handlechange(file,filelist,3)}" :on-remove="(file,filelist)=>{handleremove(file,filelist,3)}" :auto-upload="false" :file-list="filelist[2]" ref="file3" > <el-button size="small">选择图片</el-button> </el-upload> <el-button @click="submitdata">确认</el-button> <!-- action:提交的地址,此处随便写一个,不写会报错 on-change: 图片上传到缓存中将被触发 on-remove: 从缓存中删除文件将被触发 -->
data(){ filelist: [0,0,0], //缓存区文件 uploadfile:[[],[],[]] // 上传用文件 }, handlechange(file, filelist, type) { // 限制单张上传,超过限制即覆盖 if (filelist.length > 1) { filelist.splice(0, 1); } // 校验 const islt2m = file.size / 1024 / 1024 < 5; if (!islt2m) { this.$message.error("上传图片大小不能超过 5mb!"); this.removeuploadedfile(type); // 不符合要求删除文件 return false; } const isimage = file.raw.type.includes("image"); if (!isimage) { this.$message.error("上传的格式必须是图片!"); this.removeuploadedfile(type); return false; } // 验证通过之后,将缓存区文件存入上传区文件中 this.formdata.files[type] = file.raw; }, // 从缓存区移除文件 removeuploadedfile(type) { if (type === 0) { this.$refs.file1.clearfiles(); } if (type === 1) { this.$refs.file2.clearfiles(); } if (type === 2) { this.$refs.file3.clearfiles(); } } // 删除文件 handleremove(file, filelist, type) { // 删除文件时要移除缓存区文件和上传区文件 this.filelist[type] = 0; this.uploadfile[type] = []; }, // 上传文件 submitdata() { // 校验是否选择文件 let filenum = this.flatten(this.uploadfile).length; if (filenum === 0) { this.$error("未选择任何文件!"); return false; } // 使用formdata格式 let formdata = new formdata(); if (this.formdata.files[0]) { formdata.append("file1", this.formdata.files[0]); } if (this.formdata.files[1]) { formdata.append("file2", this.formdata.files[1]); } if (this.formdata.files[2]) { formdata.append("file2", this.formdata.files[2]); } // 请求:在headers上务必加上content-type,指定表单形式发送 axios .post("uploadurl", formdata, {headers: { "content-type": "multipart/form-data" }}) .then(res => { this.$success("上传图片成功!"); this.filelist = [0,0,0]; this.uploadfile =[[],[],[]]; }) .catch(e => { console.log(e); }); } // 扁平化数组 flatten(arr) { let res = []; for (let i = 0; i < arr.length; i++) { if (array.isarray(arr[i])) { res = res.concat(this.flatten(arr[i])); } else { res.push(arr[i]); } } return res; }
图片加载技术:预加载和懒加载
- 预加载:重点在"预",在用户需要看到该图片之前,就已经加载和请求到该图片。
- 懒加载: 重点在"懒",尽可能少的加载图片,只加载必需的图片(用户屏幕可视范围内),目的是尽可能的减少请求数,减缓服务器的压力。
在vue中懒加载的组件有很多,比如vue-lazy-laod
和vue-clazy-load
浏览器阻塞
同一时间对服务器的请求过多,将会造成浏览器阻塞。
浏览器默认对同一域下的资源,只保持一定的连接数,阻塞过多的连接,以提高访问速度和解决阻塞问题。
对于请求图片来说,有以下解决方法
- 使用雪碧图:把所有图片合成一张大图。
- 延迟加载:只去请求可视区的图片。
最后使用了延迟加载,对非可视区领域的图片延迟加载,优先加载可视区图片,减少图片的请求数。
<img :src="imageurl" ref="img">
// 方式一:延迟加载非可视区域 delaytime() { let windowheight = window.innerheight; let imgtop = this.$refs.img.getboundingclientrect().top; const isdelay = imgtop > windowheight; if (isdelay) { return math.random() * 2000 + 3000; } else { return math.random() * 2000 + 500; } } // 方法二:按顺序依次延迟加载 delaytime() { if (this.params.index) { return math.random() * 2000 + this.params.index * this.params.type * 500; } else { return 0; } } settimeout(() => { // 图片请求代码 }, this.delaytime);
使用延时加载前的请求
使用延时加载后的请求
参考
[1] xmlhttprequest standard.the responsetype attribute
[2] xmlhttprequest.responsetype | mdn
[3] 理解domstring、document、formdata、blob、file、arraybuffer数据类型 « 张鑫旭-鑫空间-鑫生活
[4] formdata 对象的使用 | mdn
[5] 前端|加载的图片太多或者太大怎么办(上) - u012496505的博客 - csdn博客
[6] lazy loading images and video | web fundamentals | google developers
[7] an introduction to progressive image rendering
[8] 原生 js 实现最简单的图片懒加载 - web前端 - 伯乐在线
2019/1/14 9:15:33