很多刚入门的小伙伴上传图片都会使用现成的框架,然后根据框架提供的api进行上传,感觉这样是最简单的,其实上传图片是一个很简单的功能,
点击上传图片
1.将input的设为透明然后定位到按钮上面,通过点击实现上传
<template>
<div class="page" ref="page">
<div class="uploadImg">
<div class="btn">点击上传</div>
<input type="file" ref="inputFile" accept="image/*" @change="UploadImg" class="input" />
<img :src="ImgUrl" alt="">
</div>
</div>
</template>
<script>
methods: {
UploadImg(e, code) {
// 选择原图之后
if (e.target.files[0]) {
// 及时回显到页面
let file = e.target.files[0];
this.ImgUrl = window.URL.createObjectURL(file);
// 上传到服务器
let fileFormData = new FormData();
fileFormData.append("file", file);
// 将fileFormData 通过axios 传到后台即可
// 注意要将header 进行修改 Content-Type = "multipart/form-data"
axios({
url: url,
header: {
'Content-Type': 'multipart/form-data',
},
method: 'post',
data: fileFormData
})
.then(response => {
// 返回结果
// 此处不会返回图片地址,需要我们自己使用请求地址+文件名进行拼接
let imgUrl = url + filename
})
.catch(({ data }) => {
});
//每一次提交上传图片后都清空当前input的file,防止同一张图片上传失败不能连续上传
this.$refs.inputFile.value=""
}
},
},
</script>
<style>
.uploadImg{
position:relative;
width:100px;height:30px;
}
.btn{
width:100%;height:100%;
position:absolute;top:0;left:0;
text-align: center;
line-height:30px;
border:1px solid #ccc;
}
.input{
width:100%;height:100%;position:absolute;top:0;left:0;opacity:0;
z-index:1;
}
</style>
2.点击按钮,通过处发input的点击事件后处发change,达到唤起上传图片的效果
<template>
<div>
<div class="btn" @click="triggerChange">点击上传</div>
<input type="file" ref="inputFile" accept="image/*" @change="UploadImg" @click="UploadImg" ref="uploadImage" class="input" />
</div>
</template>
<script>
methods: {
triggerChange() {
this.$refs.uploadImage.click();
},
UploadImg(e, code) {
// 选择原图之后
if (e.target.files[0]) {
// 及时回显到页面
let file = e.target.files[0];
this.ImgUrl = window.URL.createObjectURL(file);
// 上传到服务器
let fileFormData = new FormData();
fileFormData.append("file", file);
// 将fileFormData 通过axios 传到后台即可
// 注意要将header 进行修改 Content-Type = "multipart/form-data"
//axios 请求在第一种上传方法中,如有需要在上面拿一下即可,这里就不在写了
axios({})
//每一次提交上传图片后都清空当前input的file,防止同一张图片上传失败不能连续上传
this.$refs.inputFile.value=""
}
}
},
</script>
<style lang="less" scoped>
.btn{
width:100%;height:100%;
text-align: center;
line-height:30px;
border:1px solid #ccc;
}
</style>
vue 上传传oss
先通过npm安装oss依赖
npm install ali-oss --save
cnpm install ali-oss --save
oss官方文档
1.前端拿到 accessKeyId,accessKeySecret直接上传oss
这种用法会直接暴露id及secret,相当于把自己家门的钥匙告诉别人,不推荐使用
// file 从上线方法中获取到的file 传进来就可以
updateOss(file[0])
methods: {
updateOss(file){
// 请求接口得到对应的参数,这个参数不会变,项目中请求一次即可
let aliData = {
region: "oss-cn-beijing",
accessKeyId: 'your accessKeyId',
accessKeySecret: 'your accessKeySecret',
bucket: 'xx'
}
const client = new OSS(aliData);
const arr = file.name.split(".");
const suffix = arr[arr.length - 1];
const storeAs = `appupload/${file.lastModified}${Math.round( Math.random() * 10000 )}.${suffix}`;
client.multipartUpload(storeAs, file).then(({ res }) => {
if (res.status === 200) {
console.log('上传成功')
} else {
console.log('请重新上传');
}
});
},
}
2.通过后台转换,拿到对应的参数,进行上传
// file 将点击上传获取到的file传进来即可
this.updateOss(file[0])
methods: {
updateOss(file){
// 请求接口得到对应的参数
let aliData = {
accessKeyId:'',
policy:'',
signature:'',
success_action_status:'',
}
const Name = file.name
const suffix = Name.substr(Name.indexOf('.')) // 文件后缀
let filename = Date.parse(new Date()) + suffix // 组成新文件名,防止文件名冲突
let formDataKey = `文件夹/${filename}` // 文件夹是要提交的图片在oss上面的文件目录,根据项目自行配置
let formData = new FormData();
formData.append('OSSAccessKeyId', aliData.accessKeyId);
formData.append('policy', aliData.policy);
formData.append('signature', aliData.signature);
formData.append('success_action_status', aliData.success_action_status);
formData.append('key', `${formDataKey}`); //组成的文件名
formData.append('file', file);
//通过axios 请求将图片传到oss
let url="oss地址"
axios({
url: url,
header: {
'Content-Type': 'multipart/form-data',
},
method: 'post',
data: fileFormData
})
.then(response => {
// 返回结果
// 此处不会返回图片地址,需要我们自己使用请求地址+文件名进行拼接
let imgUrl = url + filename
})
.catch(({ data }) => {
});
},
}
图片裁剪
图片裁剪的插件,先通过npm安装依赖
vue-cropper 高版本解决在ios上图片拍照旋转问题
npm i vue-cropper --save
父组件
<template>
<div>
<div class="uploadImg">
<div class="btn">点击上传</div>
<input type="file" accept="image/*" @change="UploadImg" class="input" />
</div>
<img :src="ImgUrl" alt="" style="width:100%;height:auto;">
<cropperModule ref="cropperRef" @UploadCompleted="UploadCompleted" ></cropperModule>
</div>
</template>
<script>
import cropperModule from "@/components/cropper";
export default {
name: "Home",
components: {
cropperModule
},
data() {
return {
ImgUrl:'',
}
},
methods: {
UploadImg(e, code) {
if (e.target.files[0]) {
this.$refs.cropperRef.upphoto(e);
}
},
// 拿到上传完成后的图片进行渲染
UploadCompleted(imgUrl){
this.ImgUrl = imgUrl
},
},
};
</script>
<style lang="less" scoped>
.uploadImg{
position:relative;
width:100px;height:30px;
}
.btn{
width:100%;height:100%;
position:absolute;top:0;left:0;
text-align: center;
line-height:30px;
border:1px solid #ccc;
}
.input{
width:100%;height:100%;position:absolute;top:0;left:0;opacity:0;
z-index:1;
}
</style>
子组件,在项目components文件中新建一个cropper文件,在父组件中引入
<template>
<div class="upbtn">
<div class="bg" v-if="img != ''">
<div class="btndiv" v-if="config.ceilbutton">
<div
class="btn"
@click="canceltailor"
:style="
`backgroundColor:${config.cancelButtonBackgroundColor};color:${config.cancelButtonTextColor}`
"
>
{{ config.cancelButtonText }}
</div>
<div class="img" @click="rotating"></div>
<div
class="btn"
@click="tailoring"
:style="
`backgroundColor:${config.confirmButtonBackgroundColor};color:${config.confirmButtonTextColor}`
"
>
{{ config.confirmButtonText }}
</div>
</div>
<div class="wrapper">
<vueCropper
id="cropper"
ref="cropper"
:img="img"
:outputSize="config.outputSize"
:outputType="config.outputType"
:info="config.info"
:canScale="config.canScale"
:autoCrop="config.autoCrop"
:autoCropWidth="config.autoCropWidth"
:autoCropHeight="config.autoCropHeight"
:fixed="config.fixed"
:fixedNumber="config.fixedNumber"
:full="config.full"
:fixedBox="config.fixedBox"
:canMove="config.canMove"
:canMoveBox="config.canMoveBox"
:original="config.original"
:centerBox="config.centerBox"
:high="config.high"
:infoTrue="config.infoTrue"
:maxImgSize="config.maxImgSize"
:enlarge="config.enlarge"
:mode="config.mode"
@cropMoving="moving($event)"
@imgMoving="moving($event)"
></vueCropper>
</div>
<div class="btndiv" v-if="!config.ceilbutton">
<div
class="btn"
@click="canceltailor"
:style="
`backgroundColor:${config.cancelButtonBackgroundColor};color:${config.cancelButtonTextColor}`
"
>
{{ config.cancelButtonText }}
</div>
<div class="img" @click="rotating"></div>
<div
class="btn"
@click="tailoring"
:style="
`backgroundColor:${config.confirmButtonBackgroundColor};color:${config.confirmButtonTextColor}`
"
>
{{ config.confirmButtonText }}
</div>
</div>
</div>
</div>
</template>
<script>
import { VueCropper } from "vue-cropper";
export default {
name: "H5Cropper",
components: { VueCropper },
props: {
hideInput: {
type: Boolean,
default: false
},
fromType: {
type: Number,
default: 2
},
option: {
type: Object,
default() {
return {};
}
}
},
data() {
return {
img: "",
config: {},
aliData:""
};
},
watch: {
option: {
handler: function() {
//do something
delete this.option.autoCrop; // TODO: 不开放权限
if (
typeof this.option.outputType === "string" &&
["jpeg", "png", "webp"].indexOf(this.option.outputType) === -1
) {
console.warn("Option.outputType is not [jpeg, png, webp]");
delete this.option.outputType; // TODO: 改回默认属性不影响调用
}
this.config = Object.assign(this.config, this.option);
},
deep: true
}
},
created() {
// Event getFile 需要明确 MIME 类型
delete this.option.autoCrop; // TODO: 不开放权限
if (
typeof this.option.outputType === "string" &&
["jpeg", "png", "webp"].indexOf(this.option.outputType) === -1
) {
console.warn("Option.outputType is not [jpeg, png, webp]");
delete this.option.outputType; // TODO: 改回默认属性不影响调用
}
this.config = Object.assign(
{
ceilbutton: false, //顶部按钮,默认底部
outputSize: 1, //裁剪生成图片的质量
outputType: "png", //裁剪生成图片的格式,默认png
info: false, //裁剪框的大小信息
canScale: false, //图片是否允许滚轮缩放
autoCrop: false, //是否默认生成截图框
autoCropWidth: 347, //默认生成截图框宽度
autoCropHeight: 347, //默认生成截图框高度
fixed: true, //是否开启截图框宽高固定比例
fixedNumber: [1, 1], //截图框的宽高比例
full: false, //是否输出原图比例的截图
fixedBox: true, //固定截图框大小 不允许改变
canMove: true, //上传图片是否可以移动
canMoveBox: false, //截图框能否拖动
original: false, //上传图片按照原始比例渲染
centerBox: true, //截图框是否被限制在图片里面
high: true, //是否按照设备的dpr 输出等比例图片
infoTrue: true, //true 为展示真实输出图片宽高 false 展示看到的截图框宽高
maxImgSize: 2000, //限制图片最大宽度和高度
enlarge: 1, //图片根据截图框输出比例倍数
mode: "contain", //图片默认渲染方式
cancelButtonText: "取消", //取消按钮文本
confirmButtonText: "使用", //确定按钮文本
cancelButtonBackgroundColor: "#606266", //取消按钮背景色
confirmButtonBackgroundColor: "#ed594c", //确定按钮背景色
cancelButtonTextColor: "#ffffff", //取消按钮字体色
confirmButtonTextColor: "#ffffff" //确定按钮字体色
},
this.option
);
},
methods: {
//取消裁剪
canceltailor() {
this.img = "";
this.$emit("canceltailor");
},
//选择照片
async upphoto(e) {
let photourl = e.target.files[0];
if (photourl != undefined) {
this.$emit("imgorigoinf", photourl);
this.img = await this.onloadimg(photourl);
this.config.autoCrop = true;
setTimeout(() => {
this.addsolide();
}, 10);
}
},
//异步onload图片
onloadimg(photourl) {
return new Promise(function(resolve, reject) {
let reader = new FileReader();
reader.readAsDataURL(photourl);
reader.onload = e => {
resolve(e.target["result"]);
};
});
},
//确定裁剪
tailoring() {
// 获取截图的base64数据
this.$refs.cropper.getCropData(data => {
this.img = "";
this.config.autoCrop = false;
});
// 获取截图的blob数据
this.$refs.cropper.getCropBlob(data => {
// Blob 转 File
const suffix = {
jpeg: "jpg",
png: "png",
webp: "webp"
}[this.config.outputType];
const time = new Date().getTime();
const file = new File([data], `${time}.${suffix}`, {
type: `image/${this.config.outputType}`
});
// 此处获取到裁剪完成后的file
this.getFile(file);
this.img = "";
this.config.autoCrop = false;
});
},
// 获取到裁剪后的参数
getFile(file) {
let that = this;
// 此处不再赘述上传的方式,直接将file显示到页面了,上传方式在上面已经介绍过了,根据自己的项目需求引入即可
var windowURL=window.url || window.webkitURL;
let imgUrl = windowURL.createObjectURL(file);
this.$emit('UploadCompleted',imgUrl)
// axios({})
},
//旋转照片
rotating() {
this.$refs.cropper.rotateRight();
document.getElementsByClassName("cropper-modal")[0].style =
"background-color: rgba(0,0,0,0.5);transition: 0.88s";
},
//裁剪框移动
moving(e) {
if (e.moving) {
document.getElementsByClassName("cropper-modal")[0].style =
"background-color: rgba(0,0,0,0.5);transition: 0.88s";
} else {
document.getElementsByClassName("cropper-modal")[0].style =
"background-color: rgba(0,0,0,0.8);transition: 0.88s";
}
},
//添加网格线
addsolide() {
if (document.getElementById("vertical") == null) {
let box = document.getElementsByClassName("cropper-crop-box")[0];
//左网格线
let verticalLeft = document.createElement("div");
verticalLeft.id = "vertical";
verticalLeft.style.width = "1px";
verticalLeft.style.height = "100%";
verticalLeft.style.top = "0px";
verticalLeft.style.left = "33%";
verticalLeft.style.position = "absolute";
verticalLeft.style.backgroundColor = "#fff";
verticalLeft.style.zIndex = "522";
verticalLeft.style.opacity = "0.5";
//右网格线
let verticalRight = document.createElement("div");
verticalRight.style.width = "1px";
verticalRight.style.height = "100%";
verticalRight.style.top = "0px";
verticalRight.style.right = "33%";
verticalRight.style.position = "absolute";
verticalRight.style.backgroundColor = "#fff";
verticalRight.style.zIndex = "522";
verticalRight.style.opacity = "0.5";
//上网格线
let verticalTop = document.createElement("div");
verticalTop.style.width = "100%";
verticalTop.style.height = "1px";
verticalTop.style.top = "33%";
verticalTop.style.left = "0px";
verticalTop.style.position = "absolute";
verticalTop.style.backgroundColor = "#fff";
verticalTop.style.zIndex = "522";
verticalTop.style.opacity = "0.5";
//下网格线
let verticalBottom = document.createElement("div");
verticalBottom.style.width = "100%";
verticalBottom.style.height = "1px";
verticalBottom.style.bottom = "33%";
verticalBottom.style.left = "0px";
verticalBottom.style.position = "absolute";
verticalBottom.style.backgroundColor = "#fff";
verticalBottom.style.zIndex = "522";
verticalBottom.style.opacity = "0.5";
//左上边线
let LeftTopSide = document.createElement("div");
LeftTopSide.style.width = "30px";
LeftTopSide.style.height = "4px";
LeftTopSide.style.top = "-4px";
LeftTopSide.style.left = "-4px";
LeftTopSide.style.position = "absolute";
LeftTopSide.style.backgroundColor = "#fff";
LeftTopSide.style.zIndex = "522";
LeftTopSide.style.opacity = "1";
//上左边线
let TopListSide = document.createElement("div");
TopListSide.style.width = "4px";
TopListSide.style.height = "30px";
TopListSide.style.top = "-4px";
TopListSide.style.left = "-4px";
TopListSide.style.position = "absolute";
TopListSide.style.backgroundColor = "#fff";
TopListSide.style.zIndex = "522";
TopListSide.style.opacity = "1";
//右上边线
let RightTopSide = document.createElement("div");
RightTopSide.style.width = "30px";
RightTopSide.style.height = "4px";
RightTopSide.style.top = "-4px";
RightTopSide.style.right = "-4px";
RightTopSide.style.position = "absolute";
RightTopSide.style.backgroundColor = "#fff";
RightTopSide.style.zIndex = "522";
RightTopSide.style.opacity = "1";
//上右边线
let TopRightSide = document.createElement("div");
TopRightSide.style.width = "4px";
TopRightSide.style.height = "30px";
TopRightSide.style.top = "-4px";
TopRightSide.style.right = "-4px";
TopRightSide.style.position = "absolute";
TopRightSide.style.backgroundColor = "#fff";
TopRightSide.style.zIndex = "522";
TopRightSide.style.opacity = "1";
//左下边线
let LeftBottomSide = document.createElement("div");
LeftBottomSide.style.width = "30px";
LeftBottomSide.style.height = "4px";
LeftBottomSide.style.bottom = "-4px";
LeftBottomSide.style.left = "-4px";
LeftBottomSide.style.position = "absolute";
LeftBottomSide.style.backgroundColor = "#fff";
LeftBottomSide.style.zIndex = "522";
LeftBottomSide.style.opacity = "1";
//下左边线
let BottomListSide = document.createElement("div");
BottomListSide.style.width = "4px";
BottomListSide.style.height = "30px";
BottomListSide.style.bottom = "-4px";
BottomListSide.style.left = "-4px";
BottomListSide.style.position = "absolute";
BottomListSide.style.backgroundColor = "#fff";
BottomListSide.style.zIndex = "522";
BottomListSide.style.opacity = "1";
//右下边线
let RightBottomSide = document.createElement("div");
RightBottomSide.style.width = "30px";
RightBottomSide.style.height = "4px";
RightBottomSide.style.bottom = "-4px";
RightBottomSide.style.right = "-4px";
RightBottomSide.style.position = "absolute";
RightBottomSide.style.backgroundColor = "#fff";
RightBottomSide.style.zIndex = "522";
RightBottomSide.style.opacity = "1";
//下右边线
let BottomRightSide = document.createElement("div");
BottomRightSide.style.width = "4px";
BottomRightSide.style.height = "30px";
BottomRightSide.style.bottom = "-4px";
BottomRightSide.style.right = "-4px";
BottomRightSide.style.position = "absolute";
BottomRightSide.style.backgroundColor = "#fff";
BottomRightSide.style.zIndex = "522";
BottomRightSide.style.opacity = "1";
//一起生成
box.appendChild(verticalLeft);
box.appendChild(verticalRight);
box.appendChild(verticalTop);
box.appendChild(verticalBottom);
box.appendChild(LeftTopSide);
box.appendChild(TopListSide);
box.appendChild(RightTopSide);
box.appendChild(TopRightSide);
box.appendChild(LeftBottomSide);
box.appendChild(BottomListSide);
box.appendChild(RightBottomSide);
box.appendChild(BottomRightSide);
}
},
}
};
</script>
<style lang="less" scoped>
.bg {
position: fixed;
top: 0;
height: 100vh;
width: 100%;
background-color: #000;
left: 0;
z-index: 521;
}
.btn {
height: 8vw;
padding: 0;
line-height: 8vw;
font-size: 4vw;
padding: 0 3.5vw;
border-radius: 1.333vw;
text-align: center;
}
.btn1 {
height: 8vw;
line-height: 8vw;
font-size: 4vw;
padding: 0 4vw;
border-radius: 1.333vw;
text-align: center;
background-color: #5b6e96;
}
.img {
height: 8vw;
width: 8vw;
position: absolute;
left: calc(50% - 4vw);
background-image: url("data:image/png;base64,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");
background-size: 100% 100%;
}
.btndiv {
height: 13.333vw;
color: #fff;
justify-content: space-between;
display: flex;
align-items: center;
padding: 0 4vw;
line-height: 13.333vw;
font-size: 4vw;
width: 80vw;
position: absolute;
bottom: 18vh;
left: 0;
right: 0;
margin: 0 auto;
.btn {
width: 111px;
height: 36px;
padding: 0;
font-size: 16px;
line-height: 36px;
text-align: center;
border-radius: 18px;
&:nth-of-type(1) {
background: linear-gradient(180deg, #ffffff 0%, #b1daff 99%);
color: #2c3850 !important;
}
&:nth-of-type(2) {
background: linear-gradient(180deg, #ff8865, #ff4920);
}
}
.img {
height: 16vw;
width: 16vw;
left: calc(50% - 8vw);
top: 20vw;
}
}
.wrapper /deep/ .crop-point {
opacity: 0;
z-index: 523;
}
.wrapper /deep/ .cropper-view-box {
outline: 1px solid #fff;
border: 1px solid #fff;
}
.wrapper /deep/ .vue-cropper {
background-color: #000;
background-image: none;
}
.wrapper {
height: calc(100vh - 33vw);
padding: 4vw;
}
</style>