vue图片上传组件
1、正常上传
<template>
<div class="upload-wrapper">
<div v-if="!imgUrl" class="noneData">
<div @click="openLocals">
<img src="./imgs/icon_jh.png" alt="">
<div>上传图片</div>
</div>
<form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
<input ref="pathClear" type="file" accept="image/*" :name="fileName" @change="fileChanged"/>
</form>
</div>
<div v-else class="havaData">
<img :src="imgUrl" alt="" @click="actImg">
</div>
</div>
</template>
<script>
import $ from 'jquery';
import { Indicator, Toast } from 'mint-ui';
import { webPostObject } from './ossUpload/index.js';
export default {
data() {
return {
};
},
props: {
// file控件名称
fileName: {
type: String,
required: true
},
// 图片地址
imgUrl: {
type: String,
default: '',
required: true
},
},
methods: {
// 点击图片
actImg() {
console.log('点击图片');
},
// 删除图片
removePackage() {
let _self = this;
_self.$emit('removeImg');
},
// 上传图片
openLocals() {
$(`input[type='file'][name='${this.fileName}']`).click();
},
fileChanged() {
this.uploadImg();
},
uploadImg() {
let _self = this;
let fileElement = $(`input[type='file'][name='${_self.fileName}']`);
let filename = fileElement.val();
let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
Toast({
message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
position: 'bottom',
duration: 2000
});
return false;
}
let file = fileElement[0].files[0];
let imgSize = Math.ceil(file.size / 1024 / 1024);
if (imgSize > 20) {
Toast({
message: '文件不能大于20MB,重新选择文件',
position: 'bottom',
duration: 2000
});
_self.$refs.pathClear.value = '';
return false;
}
Indicator.open('图片正在上传中...');
// 服务器上传
// let formdata1 = new FormData();
// formdata1.append('file', file, file.name);
// let config = {
// headers: { 'Content-Type': 'multipart/form-data' }
// };
// axios.post(`${process.env.UPLOAD_HOST}`, formdata1, config).then((res) => {
// console.log(res);
// let data = res.data;
// Indicator.close();
// if (data) {
// _self.$emit('uploadSuccess', data[0]);
// }
// }).catch(() => {
// Indicator.close();
// Toast({
// message: '图片上传失败',
// position: 'bottom',
// duration: 2000
// });
// });
// oss web直传
webPostObject(file, file.name).then(data => {
console.log('oss web直传', data);
Indicator.close();
_self.$emit('uploadSuccess', data);
}).catch(() => {
Indicator.close();
Toast({
message: '图片上传失败',
position: 'bottom',
duration: 2000
});
});
},
},
};
</script>
<style lang="less" scoped>
.upload-wrapper{
height: 100%;
}
.noneData,.havaData{
position: relative;
height: 100%;
}
.noneData{
background-color: #eeeeee;
color: #999999;
font-size: 12px;
text-align: center;
padding-top: 15px;
img{
width: 26px;
height: 26px;
}
}
.havaData{
img{
width: 100%;
height: 100%;
}
}
</style>
2、压缩图片上传
<template>
<div class="upload-wrapper">
<div v-if="!imgUrl" class="noneData">
<div class="uploadImg" @click="openLocals">
</div>
<form :id="fileName+'Form'" enctype="multipart/form-data" style="display:none;">
<input ref="pathClear" type="file" accept="image/*" :name="fileName" @change="fileChanged"/>
</form>
</div>
<div v-else class="havaData">
<div class="havaDataimg">
<div class="img_wap">
<img :src="imgUrl" alt="" @click.stop="bigPicture">
</div>
<div class="remove" @click.stop="removePackage"></div>
</div>
</div>
<div class="maxImg" @click="minImg" v-if="maxImg">
<img :src="imgUrl" alt="">
</div>
</div>
</template>
<script>
import $ from 'jquery';
import { Indicator, Toast } from 'mint-ui';
import axios from 'axios';
export default {
data() {
return {
maxImg: false,
xhr: null,
ot: null,
oloaded: null,
};
},
props: {
// file控件名称
fileName: {
type: String,
required: true
},
// 图片地址
imgUrl: {
type: String,
default: '',
required: true
},
// 图片地址
isMaxIMg: {
type: String,
default: '',
required: true
},
},
methods: {
// 查看大图
bigPicture() {
console.log(this.isMaxIMg);
if (this.isMaxIMg === '0') {
return false;
}
this.maxImg = true;
},
// 恢复小图
minImg() {
this.maxImg = false;
},
// 删除图片
removePackage() {
let _self = this;
_self.$emit('removeImg');
},
// 上传图片
openLocals() {
$(`input[type='file'][name='${this.fileName}']`).click();
},
fileChanged() {
this.UpladFile();
},
// 三个参数
// file:一个是文件(类型是图片格式),
// w:一个是文件压缩的后宽度,宽度越小,字节越小
// objDiv:一个是容器或者回调函数
// photoCompress()
photoCompress(file, w, objDiv) {
let that = this;
let ready = new FileReader();
// 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.
ready.readAsDataURL(file);
ready.onload = function() {
let re = this.result;
that.canvasDataURL(re, w, objDiv);
};
},
canvasDataURL(path, obj, callback) {
let img = new Image();
img.src = path;
img.onload = function() {
let that = this;
// 默认按比例压缩
let w = that.width;
let h = that.height;
let scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
let quality = 0.7; // 默认图片质量为0.7
// 生成canvas
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 创建属性节点
let anw = document.createAttribute('width');
anw.nodeValue = w;
let anh = document.createAttribute('height');
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
let base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
};
},
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
convertBase64UrlToBlob(urlData) {
let arr = urlData.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
// 上传文件方法
UpladFile() {
let that = this;
let fileElement = $(`input[type='file'][name='${that.fileName}']`);
let filename = fileElement.val();
let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
Toast({
message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
position: 'bottom',
duration: 2000
});
return false;
}
let fileObj = fileElement[0].files[0];
let form = new FormData(); // FormData 对象
if (fileObj.size / 1024 > 1025) { // 大于1M,进行压缩上传
that.photoCompress(fileObj, {
quality: 0.2
}, function(base64Codes) {
let bl = that.convertBase64UrlToBlob(base64Codes);
form.append('file', bl, 'file_' + Date.parse(new Date()) + '.jpg'); // 文件对象
let config = {
headers: { 'Content-Type': 'multipart/form-data' }
};
Indicator.open('图片正在上传中...');
axios.post(`${process.env.UPLOAD_HOST}`, form, config).then((res) => {
console.log(res);
let data = res.data;
Indicator.close();
if (data) {
that.$emit('uploadSuccess', data[0]);
}
}).catch(() => {
Indicator.close();
Toast({
message: '图片过大上传失败',
position: 'bottom',
duration: 2000
});
});
});
} else { // 小于等于1M 原图上传
Indicator.open('图片正在上传中...');
form.append('file', fileObj); // 文件对象
axios.post(`${process.env.UPLOAD_HOST}`, form).then((res) => {
console.log(res);
let data = res.data;
Indicator.close();
if (data) {
that.$emit('uploadSuccess', data[0]);
}
}).catch(() => {
Indicator.close();
Toast({
message: '图片过大上传失败',
position: 'bottom',
duration: 2000
});
});
}
},
}
};
</script>
<style lang="less" scoped>
.upload-wrapper{
position: relative;
height: 172px;
}
.noneData,.havaData{
height: 100%;
padding: 15px 16vw;
position: relative;
display: flex;
justify-content: center;
align-items: center;
.uploadImg{
width: 102px;
height: 102px;
background-size: 100% 100%;
background-image: url(./imgs/xh_pfgy_upload.png);
}
.havaDataimg{
position: relative;
width: 100%;
height: 100%;
border: 1px solid #eeeeec;
overflow: hidden;
.img_wap{
width: 100%;
height: 0px;
padding-bottom: 56%;
position: relative;
img{
width: 100%;
position: absolute;
top: -30%;
left: 0px;
}
}
.remove{
position: absolute;
top: 0;
right: 0;
width: 18px;
height: 18px;
background: url('./imgs/icon_close.png') rgba(255, 255, 255, 0.8) center center no-repeat;
background-size: cover;
border-radius: 50%;
}
}
}
// 大图效果
.maxImg{
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
overflow: auto;
background-color:rgba(0, 0, 0, 0.5);
z-index: 100;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
img{
max-width: 100%;
max-height: 100%;
}
}
</style>
3、转为base64上传
<template>
<div>
<div style="padding:20px;">
<!-- <div class="show">
<div class="picture" :style="'backgroundImage:url('+headerImage+')'"></div>
</div> -->
<div class="havaDataimg">
<div class="img_wap">
<img :src="headerImage" alt="">
</div>
<div class="remove"></div>
</div>
<div style="margin-top:20px;">
<input type="file" id="upload" accept="image/*" @change="upload">
<label for="upload"></label>
</div>
</div>
</div>
</template>
<script>
import Exif from 'exif-js';
import { Toast } from 'mint-ui';
export default {
data() {
return {
headerImage: '',
picValue: ''
};
},
methods: {
upload(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length) return;
this.picValue = files[0];
let filename = this.picValue.name;
let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
if (ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg' && ext !== '.bmp') {
Toast({
message: '仅支持.jpg、.png、.jpeg、.bmp的图片格式',
position: 'bottom',
duration: 2000
});
return false;
}
this.imgPreview(this.picValue);
},
imgPreview(file) {
let self = this;
let Orientation;
// 去获取拍照时的信息,解决拍出来的照片旋转问题
Exif.getData(file, function() {
Orientation = Exif.getTag(this, 'Orientation');
});
// 看支持不支持FileReader
if (!file || !window.FileReader) return;
if (/^image/.test(file.type)) {
// 创建一个reader
let reader = new FileReader();
// 将图片2将转成 base64 格式
reader.readAsDataURL(file);
// 读取成功后的回调
reader.onloadend = function () {
let result = this.result;
let img = new Image();
img.src = result;
// 判断图片是否大于100K,是就直接上传,反之压缩图片
if (this.result.length <= (100 * 1024)) {
self.headerImage = this.result;
self.postImg();
} else {
img.onload = function () {
let data = self.compress(img, Orientation);
self.headerImage = data;
self.postImg();
};
}
};
}
},
postImg() {
// 这里写接口
},
rotateImg(img, direction, canvas) {
// 最小与最大旋转方向,图片旋转4次后回到原方向
const min_step = 0;
const max_step = 3;
if (img == null) return;
// img的高度和宽度不能在img元素隐藏后获取,否则会出错
let height = img.height;
let width = img.width;
let step = 2;
if (step == null) {
step = min_step;
}
if (direction === 'right') {
step++;
// 旋转到原位置,即超过最大值
step > max_step && (step = min_step);
} else {
step--;
step < min_step && (step = max_step);
}
// 旋转角度以弧度值为参数
let degree = step * 90 * Math.PI / 180;
let ctx = canvas.getContext('2d');
switch (step) {
case 0:
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0);
break;
case 1:
canvas.width = height;
canvas.height = width;
ctx.rotate(degree);
ctx.drawImage(img, 0, -height);
break;
case 2:
canvas.width = width;
canvas.height = height;
ctx.rotate(degree);
ctx.drawImage(img, -width, -height);
break;
case 3:
canvas.width = height;
canvas.height = width;
ctx.rotate(degree);
ctx.drawImage(img, -width, 0);
break;
}
},
compress(img, Orientation) {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 瓦片canvas
let tCanvas = document.createElement('canvas');
let tctx = tCanvas.getContext('2d');
let initSize = img.src.length;
let width = img.width;
let height = img.height;
// 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
let ratio;
if ((ratio = width * height / 4000000) > 1) {
console.log('大于400万像素');
ratio = Math.sqrt(ratio);
width /= ratio;
height /= ratio;
} else {
ratio = 1;
}
canvas.width = width;
canvas.height = height;
// 铺底色
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 如果图片像素大于100万则使用瓦片绘制
let count;
if ((count = width * height / 1000000) > 1) {
console.log('超过100W像素');
count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片
// 计算每块瓦片的宽和高
let nw = ~~(width / count);
let nh = ~~(height / count);
tCanvas.width = nw;
tCanvas.height = nh;
for (let i = 0; i < count; i++) {
for (let j = 0; j < count; j++) {
tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
}
}
} else {
ctx.drawImage(img, 0, 0, width, height);
}
// 修复ios上传图片的时候 被旋转的问题
if (Orientation !== '' && Orientation !== 1) {
switch (Orientation) {
case 6:// 需要顺时针(向左)90度旋转
this.rotateImg(img, 'left', canvas);
break;
case 8:// 需要逆时针(向右)90度旋转
this.rotateImg(img, 'right', canvas);
break;
case 3:// 需要180度旋转
this.rotateImg(img, 'right', canvas);// 转两次
this.rotateImg(img, 'right', canvas);
break;
}
}
// 进行最小压缩
let ndata = canvas.toDataURL('image/jpeg', 0.7);
console.log('压缩前:' + initSize);
console.log('压缩后:' + ndata.length);
console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + '%');
tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
return ndata;
},
}
};
</script>
<style lang="less" scoped>
*{
margin: 0;
padding: 0;
}
/* .show {
width: 100px;
height: 100px;
overflow: hidden;
position: relative;
border-radius: 50%;
border: 1px solid #d5d5d5;
}
.picture {
width: 100%;
height: 100%;
overflow: hidden;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
} */
.havaDataimg{
position: relative;
width: 100%;
height: 100%;
border: 1px solid #eeeeec;
overflow: hidden;
.img_wap{
width: 100%;
height: 0px;
position: relative;
padding-bottom: 56.25%;
img{
width: 100%;
position: absolute;
top: -30%;
left: 0px;
}
}
}
</style>
4引入组件使用
import uploadImg from '@/components/upload/prescriptionUploadImg';
components: {
'uploadImg': uploadImg,
},
<uploadImg :imgUrl="pic_url" :fileName="'Image'" @uploadSuccess="addImgUrl" @removeImg="removeImgUrl"></uploadImg>

浙公网安备 33010602011771号