图片裁剪
安装cropperjs插件 (下面有cropperjs使用文档)
yarn add cropperjs
上传图片按钮
<!-- 上传图片按钮 -->
<div class="btn-item" @click="uploadImg">上传图片</div>
<input type="file" hiddenref="uploadImg" name="file" accept="image/*" @change="fileChange" />
<!-- 使用图片裁剪组件 -->
<previewImageLayer
v-if="showPreviewImageLayer"
:imgSrc="imgSrc"
@newImgUrl="newImgUrl"
:showPreviewImageLayer.sync="showPreviewImageLayer"
></previewImageLayer>
uploadImg() {
this.$refs.uploadImg.click();
},
fileChange(event) {
//读取上传文件
let reader = new FileReader();
if (event.target.files[0]) {
//readAsDataURL方法可以将File对象转化为data:URL格式的字符串(base64编码)
reader.readAsDataURL(event.target.files[0]);
reader.onload = (e) => {
console.log(e, "e");
let dataURL = reader.result;
//将img的src改为刚上传的文件的转换格式
this.imgSrc = dataURL;
this.showPreviewImageLayer = true;
};
}
},
//裁剪后的图片
newImgUrl(val) {
this.imgSrc = val;
},
封装图片裁剪组件
参数 | 描述 |
---|---|
imgSrc | 父组件传过来的图片地址 |
cropperImgUrl | 裁剪完成的图片的地址 |
newImgUrl | 裁剪完成的图片(子传父) |
<template>
<div class="maskLayer" v-if="showPreviewImageLayer">
<div class="saveItemLayer dialogCon">
<div class="dcTitle">
<p class="title">编辑图片</p>
<p class="close" v-on:click="handleCloseLayer">
<i class="el-icon-close"></i>
</p>
</div>
<div class="silCon">
<div class="img">
<img id="cropImg" :src="imgSrc" />
</div>
<!-- 两个用于预览的div -->
<div class="wrap">
<div class="previewText">裁剪预览</div>
<div class="previewBox"></div>
<div class="previewBoxRound"></div>
</div>
</div>
<canvas id="toCanvas" ref="toCanvas"></canvas>
<div class="dcBottom">
<!-- 自己配置功能 -->
<p class="item" @click="rotate">旋转</p>
<p class="input" style="width:240px">
<span>缩放倍数<span style="color:#f00;font-size: 12px;">(正数放大,负数缩小,可以为小数)</span></span
><el-input v-model="zoomVal" placeholder="输入缩放倍数"></el-input>
</p>
<p class="item" @click="zoom">缩放</p>
<p class="item" @click="reset">重置</p>
<p class="item" v-on:click="handleSaveItem">确定</p>
<p class="item" v-on:click="handleCloseLayer">取消</p>
</div>
</div>
</div>
</template>
<script>
//引入Cropper.js
import "cropperjs/dist/cropper.css";
import Cropper from "cropperjs";
export default {
data() {
return {
radio: 0,
CROPPER: null,
zoomVal: 0.1,
cropperImgUrl:''
};
},
props: {
imgSrc: {
type: String,
default: null,
},
showPreviewImageLayer: {
type: Boolean,
default: false,
},
},
mounted() {
this.init();
},
methods: {
init() {
const image = document.getElementById("cropImg");
//创建cropper实例
this.CROPPER = new Cropper(image, {
aspectRatio: 16 / 16,
viewMode: 0,
minContainerWidth: 600,
minContainerHeight: 600,
dragMode: "move",
preview: [
document.querySelector(".previewBox"),
document.querySelector(".previewBoxRound"),
],
});
},
handleSaveItem() {
//getCroppedCanvas方法可以将裁剪区域的数据转换成canvas数据
this.CROPPER.getCroppedCanvas({
maxWidth: 4096,
maxHeight: 4096,
fillColor: "#fff",
imageSmoothingEnabled: true,
imageSmoothingQuality: "high",
}).toBlob((blob) => {
//使用 URL.createObjectURL() 方法将blob转化为一个 URL
this.cropperImgUrl = URL.createObjectURL(blob);
this.$emit('newImgUrl',this.cropperImgUrl)
this.$emit("update:showPreviewImageLayer", false);
});
},
rotate() {
this.CROPPER.rotate(90);
},
zoom() {
this.CROPPER.zoom(this.zoomVal);
},
reset() {
this.CROPPER.reset();
},
handleCloseLayer() {
this.$emit("update:showPreviewImageLayer", false);
},
},
created() {},
};
</script>
<style lang="scss" scoped>
.maskLayer {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
position: fixed;
left: 0;
top: 0;
z-index: 999;
.dialogCon {
width: 1200px;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 6px 6px 0px 0px;
padding-bottom: 80px;
.dcTitle {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 49px;
color: #214361;
border-bottom: 1px solid rgba(149, 161, 184, 0.2);
border-radius: 6px 6px 0px 0px;
.title {
font-size: 20px;
font-weight: bold;
color: #214361;
margin-left: 15px;
}
.close {
margin-right: 30px;
cursor: pointer;
i {
font-size: 16px;
}
}
}
.silCon {
width: 100%;
height: 660px;
padding-top: 40px;
padding-left: 27px;
padding-bottom: 40px;
display: flex;
align-items: center;
.img {
flex: 1;
height: 100%;
margin-right: 20px;
img {
width: 100%;
height: 100%;
}
}
.wrap {
width: 200px;
.previewBox,
.previewBoxRound {
box-shadow: 0 0 5px #adadad;
width: 150px;
height: 150px;
margin-top: 30px;
overflow: hidden; /*这个超出设置为隐藏很重要,否则就会整个显示出来了*/
}
.previewBoxRound {
border-radius: 50%; /*设置为圆形*/
}
}
}
.dcBottom {
position: absolute;
left: 0;
bottom: 0;
display: flex;
justify-content: end;
align-items: center;
width: 100%;
height: 60px;
background: #fafafa;
border-top: 1px solid rgba(149, 161, 184, 0.2);
margin-bottom: 0;
.input {
display: flex;
flex-direction: column;
width: 200px;
margin-left: 10px;
margin-right: 10px;
}
.item {
width: 80px;
height: 30px;
color: #fff;
font-size: 14px;
line-height: 30px;
text-align: center;
background: #38c8c0;
cursor: pointer;
&:nth-child(1) {
margin-right: 10px;
}
&:last-child {
margin-right: 20px;
color: #214361;
background: #fafafa;
border: 1px solid #dee4e9;
}
}
}
}
}
</style>
cropperjs
使用文档
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
this.myCropper = new Cropper('被裁剪对象', '配置对象') //返回一个cropper对象
//用法
this.myCropper.zoom(0.1) //(正数放大,负数缩小,可以为小数)单位为数字,0.1为在原缩放基础上增加0.1倍
this.myCropper.rotate(90) //旋转图片,单位为数字,90为顺时针旋转90度
-
配置对象
viewMode
视图控制- 0 无限制
- 1 限制裁剪框不能超出图片的范围
- 2 限制裁剪框不能超出图片的范围 且图片填充模式为 cover 最长边填充
- 3 限制裁剪框不能超出图片的范围 且图片填充模式为 contain 最短边填充
dragMode
拖拽图片模式- crop 形成新的裁剪框
- move 图片可移动
- none 什么也没有
initialAspectRatio
裁剪框宽高比的初始值 默认与图片宽高比相同 只有在aspectRatio没有设置的情况下可用aspectRatio
设置裁剪框为固定的宽高比data
之前存储的裁剪后的数据 在初始化时会自动设置 只有在autoCrop设置为true时可用preview
预览 设置一个区域容器预览裁剪后的结果- Element, Array (elements), NodeList or String (selector)
responsive
在窗口尺寸调整后 进行响应式的重渲染 默认truerestore
在窗口尺寸调整后 恢复被裁剪的区域 默认truecheckCrossOrigin
检查图片是否跨域 默认true 如果是 会在被复制的图片元素上加上属性crossOrigin 并且在src上加上一个时间戳 避免重加载图片时因为浏览器缓存而加载错误checkOrientation
检查图片的方向信息(仅JPEG图片有)默认true 在旋转图片时会对图片方向值做一些处理 以解决IOS设备上的一些问题modal
是否显示图片和裁剪框之间的黑色蒙版 默认trueguides
是否显示裁剪框的虚线 默认truecenter
是否显示裁剪框中间的 ‘+’ 指示器 默认truehighlight
是否显示裁剪框上面的白色蒙版 (很淡)默认truebackground
是否在容器内显示网格状的背景 默认trueautoCrop
允许初始化时自动的裁剪图片 配合 data 使用 默认trueautoCropArea
设置裁剪区域占图片的大小 值为 0-1 默认 0.8 表示 80%的区域movable
是否可以移动图片 默认truerotatable
是否可以旋转图片 默认truescalable
是否可以缩放图片(可以改变长宽) 默认truezoomable
是否可以缩放图片(改变焦距) 默认truezoomOnTouch
是否可以通过拖拽触摸缩放图片 默认truezoomOnWheel
是否可以通过鼠标滚轮缩放图片 默认truewheelZoomRatio
设置鼠标滚轮缩放的灵敏度 默认 0.1cropBoxMovable
是否可以拖拽裁剪框 默认truecropBoxResizable
是否可以改变裁剪框的尺寸 默认truetoggleDragModeOnDblclick
是否可以通过双击切换拖拽图片模式(move和crop)默认true 当拖拽图片模式为none时不可切换 该设置必须浏览器支持双击事件minContainerWidth(200)、minContainerHeight(100)、minCanvasWidth(0)、minCanvasHeight(0)、minCropBoxWidth(0)、minCropBoxHeight(0)
容器、图片、裁剪框的 最小宽高 括号内为默认值 注意 裁剪框的最小高宽是相对与页面而言的 并非相对图片方法使用
crop()
手动显示裁剪框reset()
重置图片和裁剪框为初始状态replace(url[, hasSameSize])
替换图片路径并且重建裁剪框- url 新路径
- hasSameSize 默认值false 设置为true表示新老图片尺寸一样 只需要更换路径无需重建裁剪框
enable()
解冻 裁剪框disable()
冻结 裁剪框destroy()
摧毁裁剪框并且移除cropper实例move(offsetX[, offsetY])
移动图片指定距离 一个参数代表横纵向移动距离一样moveTo(x[, y])
移动图片到一个指定的点 一个参数代表横纵向移动距离一样zoom(ratio)
缩放 ratio大于零是放大 小于零缩小zoomTo(ratio[, pivot])
缩放并设置中心点的位置rotate(degree)
旋转 类似cssrotateTo(degree)
旋转到绝对角度scale(scaleX[, scaleY])、scaleX(scaleX)、scaleY(scaleY)
缩放 一个参数代表横纵向缩放值一样getData([rounded])
返回裁剪区域基于原图片!原尺寸!的位置和尺寸 rounded默认为false 表示是否显示四舍五入后的数据 有了这些数据可以直接在原图上进行裁剪显示setData(data)
改变裁剪区域基于原图的位置和尺寸 仅当viewMode 不为0时有效getContainerData()、getImageData()、getCanvasData()、setCanvasData(data)、getCropBoxData()、setCropBoxData(data)
容器、图片容器(画布)、图片、裁剪区域相对容器的数据设置和获取getCroppedCanvas([options])
得到被裁剪图片的一个canvas对象 options设置这个canvas的一些数据- width、height、minWidth、minHeight、maxWidth、maxHeight、fillColor、imageSmoothingEnabled(图片是否是光滑的 默认true)、imageSmoothingQuality(图片的质量 默认low 还有medium、high)
setAspectRatio(aspectRatio)
改变裁剪区域的宽高比setDragMode([mode])
设置拖拽图片模式事件
ready
渲染前(图片已经被加载、cropper实例已经准备完毕)的准备工作事件cropstart、cropmove、cropend、crop
开始画裁剪框(或画布)、画裁剪框(或画布)的中途、裁剪框(或画布)画完、进行裁剪事件 event.detail.originalEvent、event.detail.action- 当autoCrop为true crop事件会在ready之前触发
zoom
裁剪框缩放事件