上传图片之前,按照一定比例进行剪裁,剪裁后上传到服务器
官方地址
安装
npm install vue-cropper
<template>
<div class="show-info">
<div class="test test1">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:fixedBox="option.fixedBox"
:original="option.original"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:centerBox="option.centerBox"
:high="option.high"
:infoTrue="option.infoTrue"
@realTime="realTime"
@imgLoad="imgLoad"
@cropMoving="cropMoving"
:enlarge="option.enlarge"
></vueCropper>
</div>
<div class="test-button">
<button @click="changeImg" class="btn">随机图片</button>
<label class="btn" for="uploads">上传图片</label>
<input
type="file"
id="uploads"
style="position: absolute; clip: rect(0 0 0 0)"
accept="image/png, image/jpeg, image/gif, image/jpg"
@change="uploadImg($event, 1)"
/>
<button @click="startCrop" v-if="!crap" class="btn">开始裁剪</button>
<button @click="stopCrop" v-else class="btn">停止裁剪</button>
<button @click="clearCrop" class="btn">清除</button>
<button @click="refreshCrop" class="btn">刷新</button>
<button @click="changeScale(1)" class="btn">放大</button>
<button @click="changeScale(-1)" class="btn">缩小</button>
<button @click="rotateLeft" class="btn">左旋转</button>
<button @click="rotateRight" class="btn">右旋转</button>
<button @click="finish('base64')" class="btn">生成图片base64</button>
<button @click="finish('blob')" class="btn">生成图片blob</button>
<a @click="down('base64')" class="btn">base64下载</a>
<a @click="down('blob')" class="btn">blob下载</a>
<a :href="downImg" download="demo.png" ref="downloadDom">{{ downImg }}</a>
</div>
<!-- -->
<div class="box">
<div class="input">
<h3>输出图片</h3>
<div
class="show-preview"
:style="{ width: previews.w + 'px', height: previews.h + 'px', overflow: 'hidden', margin: '5px' }"
>
<div :style="previews.div">
<img :src="previews.url" :style="previews.img" />
</div>
</div>
</div>
<el-row >
<el-col :span="12" class="c-item">
<span>上传图片是否显示原始宽高 (针对大图 可以铺满)</span>
<input type="checkbox" v-model="option.original" />
<span>original: {{ option.original }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>是否根据dpr生成适合屏幕的高清图片</span>
<input type="checkbox" v-model="option.high" />
<span>high: {{ option.high }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>是否输出原图比例的截图</span>
<input type="checkbox" v-model="option.full" />
<span>full: {{ option.full }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>截图信息展示是否是真实的输出宽高</span>
<input type="checkbox" v-model="option.infoTrue" />
<span>infoTrue: {{ option.infoTrue }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>能否拖动图片</span>
<input type="checkbox" v-model="option.canMove" />
<span>canMove: {{ option.canMove }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>能否拖动截图框</span>
<input type="checkbox" v-model="option.canMoveBox" />
<span>canMoveBox: {{ option.canMoveBox }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>截图框固定大小</span>
<input type="checkbox" v-model="option.fixedBox" />
<span>fixedBox: {{ option.fixedBox }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>是否自动生成截图框</span>
<input type="checkbox" v-model="option.autoCrop" />
<span>autoCrop: {{ option.autoCrop }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>截图框是否限制在图片里(只有在自动生成截图框时才能生效)</span>
<input type="checkbox" v-model="option.centerBox" />
<span>centerBox: {{ option.centerBox }}</span>
</el-col>
<el-col :span="12" class="c-item">
<span>是否按照截图框比例输出 默认为1 </span>
<input type="number" v-model="option.enlarge" />
</el-col>
<el-col :span="12" class="c-item">
<span>输出图片格式 </span>
<label><input type="radio" name="type" value="jpeg" v-model="option.outputType" />jpeg </label>
<label><input type="radio" name="type" value="jpg" v-model="option.outputType" />jpg </label>
<label> <input type="radio" name="type" value="png" v-model="option.outputType" />png</label>
<label> <input type="radio" name="type" value="webp" v-model="option.outputType" />webp</label>
</el-col>
</el-row>
</div>
<div slot="body">{{ code1 }}</div>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
components: {
VueCropper,
},
data() {
return {
// 初始化值
option: {
size: 1,
full: true, // 是否输出原图比例的截图
canMove: true, // 上传图片是否可以移动
fixedBox: false, // 固定截图框大小 不允许改变
original: false, // 上传图片按照原始比例渲染
canMoveBox: true, // 截图框能否拖动
img: 'https://avatars3.githubusercontent.com/u/15681693', // url 地址 || base64 || blob null
outputSize: 1, // 裁剪生成图片的质量 1 (0-1)
outputType: 'jpg', // 裁剪生成图片的格式 jpg (jpg 需要传入jpeg)
info: '', // 裁剪框的大小信息 true
canScale: true, // 图片是否允许滚轮缩放 true
autoCrop: true, // 是否默认生成截图框 false
fixed: true, // 是否开启截图框宽高固定比例 true
// 只有自动截图开启 宽度高度才生效
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 150, // 默认生成截图框高度
centerBox: true, // 截图框是否被限制在图片里面
high: true, // 是否按照设备的dpr 输出等比例图片
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
w: 200,
h: 200,
maxImgSize: 1200, // 限制图片最大宽度和高度
// enlarge:1, //图片根据截图框输出比例倍数
// fixedNumber:[1,1] // 截图框的宽高比例
// mode: 'contain',
},
// 截图后值
previews: {},
crap: false,
previewStyle1: {},
previewStyle2: {},
code1: '',
lists: [
{
img: 'https://img2.baidu.com/it/u=2102736929,2417598652&fm=26&fmt=auto&gp=0.jpg',
},
{
img: 'https://img0.baidu.com/it/u=1330784235,4146572500&fm=26&fmt=auto&gp=0.jpg',
},
{
img: 'https://img0.baidu.com/it/u=4015235454,569502415&fm=26&fmt=auto&gp=0.jpg',
},
{
img: 'https://img2.baidu.com/it/u=3566088443,3713209594&fm=26&fmt=auto&gp=0.jpg',
},
{
img: 'https://img0.baidu.com/it/u=3870964477,3746012709&fm=26&fmt=auto&gp=0.jpg',
},
{
img: 'https://img2.baidu.com/it/u=360400461,2955275651&fm=26&fmt=auto&gp=0.jpg',
},
],
index: 0,
downImg: '',
}
},
mounted() {
console.log(window['vue-cropper'])
},
methods: {
// 上传图片
uploadImg(val, num) {
console.log(val, num)
const file = val.target.files[0]
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(val.target.value)) {
console.log('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
return false
}
const reader = new FileReader()
reader.onload = e => {
let data
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
data = e.target.result
}
if (num === 1) {
this.option.img = data
} else if (num === 2) {
this.example2.img = data
}
this.previews = this.option
console.log(this.option.img)
}
// 转化为base64
// reader.readAsDataURL(file)
// 转化为blob
reader.readAsArrayBuffer(file)
},
imgLoad(val) {
console.log(val)
},
// 截图框移动回调函数
cropMoving(val) {
console.log(val)
},
changeImg(val) {
const num = Math.ceil(Math.random() * this.lists.length)
console.log(val, num, this.lists[num].img)
this.option.img = this.lists[num].img
},
// 开始截图
startCrop() {
this.crap = true
this.$refs.cropper.startCrop()
},
// 停止截图
stopCrop() {
this.crap = false
this.$refs.cropper.stopCrop()
},
// 清除截图
clearCrop() {
this.$refs.cropper.clearCrop()
},
// 刷新
refreshCrop(val) {
console.log(val)
this.$refs.cropper.refresh()
},
// 修改图片大小 正数为变大 负数变小
changeScale(val) {
console.log(val)
const num = val || 1
this.$refs.cropper.changeScale(num)
},
// 向右边旋转90度
rotateLeft(val) {
console.log(val)
this.$refs.cropper.rotateRight()
},
// 向左边旋转90度
rotateRight(val) {
console.log(val)
this.$refs.cropper.rotateLeft()
},
// 获取截图信息
getInfo() {
const W = this.$refs.cropper.cropW // 截图框宽度
const H = this.$refs.cropper.cropH // 截图框高度
console.log(W, H)
},
// down 下载
down(val) {
console.log(val)
const aLink = document.createElement('a')
aLink.download = 'demo'
// 输出
if (val === 'blob') {
// 获取截图的blob数据
this.$refs.cropper.getCropBlob(data => {
this.downImg = window.URL.createObjectURL(data)
aLink.href = window.URL.createObjectURL(data)
aLink.click()
})
} else {
// 获取截图的base64 数据
this.$refs.cropper.getCropData(data => {
this.downImg = data
aLink.href = data
aLink.click()
})
}
},
// 输出
finish(val) {
console.log(val)
// const test = window.open('about:blank')
// test.document.body.innerHTML = '图片生成中..'
if (val === 'blob') {
this.$refs.cropper.getCropBlob(data => {
const img = window.URL.createObjectURL(data)
this.model = true
this.modelSrc = img
})
} else {
this.$refs.cropper.getCropData(data => {
this.model = true
this.modelSrc = data
})
}
},
// 添加预览
realTime(data) {
console.log(data)
this.previews = data
},
// 获取图片基于容器的坐标点
getImgAxis(val) {
console.log(val)
this.$refs.cropper.getImgAxis()
},
// 获取截图框基于容器的坐标点
getCropAxis(val) {
console.log(val)
this.$refs.cropper.getCropAxis()
},
// 自动生成截图框函数
goAutoCrop(val) {
const go = this.$refs.cropper.goAutoCrop
console.log(val, go)
},
finish2(type) {
console.log(type)
this.$refs.cropper2.getCropData(data => {
this.model = true
this.modelSrc = data
})
},
finish3(type) {
console.log(type)
this.$refs.cropper3.getCropData(data => {
this.model = true
this.modelSrc = data
})
},
},
}
</script>
<style lang="scss" scoped>
.box {
display: flex;
}
.cut {
width: 500px;
height: 500px;
margin: 30px auto;
}
.c-item {
max-width: 500px;
margin: 10px auto;
margin-top: 12px;
}
.content {
margin: auto;
max-width: 1200px;
margin-bottom: 100px;
}
.test-button {
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: center;
}
.set{
display: flex;
}
.btn {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #c0ccda;
color: #1f2d3d;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 20px 10px 0px 0px;
padding: 9px 15px;
font-size: 14px;
border-radius: 4px;
color: #fff;
background-color: #50bfff;
border-color: #50bfff;
transition: all 0.2s ease;
text-decoration: none;
user-select: none;
}
.des {
line-height: 30px;
}
code.language-html {
padding: 10px 20px;
margin: 10px 0px;
display: block;
background-color: #333;
color: #fff;
overflow-x: auto;
font-family: Consolas, Monaco, Droid, Sans, Mono, Source, Code, Pro, Menlo, Lucida, Sans, Type, Writer, Ubuntu, Mono;
border-radius: 5px;
white-space: pre;
}
.show-info {
margin-bottom: 10px;
margin-top: 10px;
}
.show-info h2 {
line-height: 50px;
}
/*.title, .title:hover, .title-focus, .title:visited {
color: black;
}*/
.title {
display: block;
text-decoration: none;
text-align: center;
line-height: 1.5;
margin: 20px 0px;
background-image: -webkit-linear-gradient(
left,
#3498db,
#f47920 10%,
#d71345 20%,
#f7acbc 30%,
#ffd400 40%,
#3498db 50%,
#f47920 60%,
#d71345 70%,
#f7acbc 80%,
#ffd400 90%,
#3498db
);
color: transparent;
-webkit-background-clip: text;
background-size: 200% 100%;
animation: slide 5s infinite linear;
font-size: 40px;
}
.test {
height: 500px;
}
.model {
position: fixed;
z-index: 10;
width: 100vw;
height: 100vh;
overflow: auto;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
.model-show {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.model img {
display: block;
margin: auto;
max-width: 80%;
user-select: none;
background-position: 0px 0px, 10px 10px;
background-size: 20px 20px;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee 100%),
linear-gradient(45deg, #eee 25%, white 25%, white 75%, #eee 75%, #eee 100%);
}
.c-item {
display: block;
user-select: none;
}
@keyframes slide {
0% {
background-position: 0 0;
}
100% {
background-position: -100% 0;
}
}
</style>