第一次做上传剪裁图片,找了许多框架,最后找到一个优雅的图片裁剪插件vue-cropper,很方便新手入手
安装
npm install vue-cropper
使用
import VueCropper from vue-cropper
import axios from 'axios'
const host = 'xxx';
//预上传
export function uploadBefore(md5, size, ext) {
const url = host + "/file/upload/before";
return axios.post(url, {
md5: md5,
size: size,
ext: ext
}).then((res) => {
return Promise.resolve(res)
})
}
//保存文件
export function saveImage(key) {
const url = host + "/file/save";
return axios.put(url, {
key: key
}).then((res) => {
return Promise.resolve(res)
})
}
import * as qiniu from 'qiniu-js'
import browserMD5File from 'browser-md5-file'
import { uploadBefore as preUploadFile, saveImage as saveFile } from 'api/uploadImage'
export function uploadFile(file) {
return new Promise((resolve, reject) => {
function checkError(res) {
if (res.data.code !== 0) {
reject(new Error(res.data.msg))
}
}
// 预上传
new Promise(preResolve => {
// 生成文件 MD5 以便校验服务器上是否存在该文件
browserMD5File(file, function (err, md5) {
// size 转换成 kb
const size = file.size / 1024
const ext = file.name.substr(file.name.lastIndexOf('.') + 1)
preUploadFile(md5, size, ext).then(res => {
checkError(res)
// 当 file_id 存在时表示文件已经上传过,所以进行秒传处理
if (res.data.data.file_id) {
resolve(res.data.data)
} else {
preResolve(res.data.data)
}
})
})
}).then(res => {
let observable = qiniu.upload(file, res.key, res.token)
return new Promise((uploadResolve, uploadReject) => {
observable.subscribe({
next(res) {
},
error(err) {
uploadReject(err)
},
complete(res) {
uploadResolve(res)
}
})
})
}).then(res => {
const key = res.key
return saveFile(key)
}).then(res => {
checkError(res)
resolve(res.data.data)
}).catch(e => {
console.log(e)
this.$message.warning(e.message)
})
})
}
<template>
<div>
<!-- element 上传图片按钮 -->
<el-upload class="uploader"
action
:show-file-list="false"
:on-success="handleUploadSuccess"
:http-request="customUpload">
<img v-if="fileinfo.url"
:src="fileinfo.url"
class="upload">
<i v-else
class="el-icon-plus uploader-icon" />
</el-upload>
......
<!-- vueCropper 剪裁图片实现-->
<div class="vue-cropper-box"
v-if="isShowCropper">
<div class="vue-cropper-content">
<vueCropper ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"></vueCropper>
</div>
<el-button v-if="isShowCropper"
type="danger"
@click="onCubeImg">确定裁剪图片</el-button>
</div>
</div>
</template>
<script>
import VueCropper from "vue-cropper"
import { uploadFile } from './uploadFile'
export default {
components: {
VueCropper
},
data() {
return {
//裁剪组件的基础配置option
option: {
img: '', //裁剪图片的地址
info: true, //裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量
outputType: 'jpeg', //裁剪生成图片的格式
canScale: false, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 150, // 默认生成截图框宽度
autoCropHeight: 150, // 默认生成截图框高度
fixed: false, //是否开启截图框宽高固定比例
fixedNumber: [4, 4] //截图框的宽高比例
},
isShowCropper: false, //是否显示截图框
fileUpload: null,
fileinfo: {},
form: {},
}
},
methods: {
//上传按钮上传成功执行事件
handleUploadSuccess(response, file, fileList) {
this.log('Upload response is %o', response)
this.fileinfo = response
this.fileUpload = file;
//上传成功后将图片地址赋值给裁剪框显示图片
this.$nextTick(() => {
this.option.img = file.url;
this.isShowCropper = true
})
},
// 确定裁剪图片
onCubeImg() {
// 获取cropper的截图的base64 数据
this.$refs.cropper.getCropData(data => {
this.fileinfo.url = data
this.isShowCropper = false
//先将显示图片地址清空,防止重复显示
this.option.img = ''
//将剪裁后base64的图片转化为file格式
let file = this.convertBase64UrlToBlob(data)
file.name = this.fileUpload.name
//将剪裁后的图片执行上传
this.uploadFile(file).then(res => {
this.form.content = res.file_id //将上传的文件id赋值给表单from的content
})
})
},
// 将base64的图片转换为file文件
convertBase64UrlToBlob(urlData) {
let bytes = window.atob(urlData.split(',')[1]);//去掉url的头,并转换为byte
//处理异常,将ascii码小于0的转换为大于0
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], { type: 'image/jpeg' });
},
代码暂时都是从项目中抽出来的,只适合借鉴参考,等有时间再单独将这些功能单独写项目,欢迎大家提供更好用的方法或指出不足之处,一起进步。
2019-11-07最新更新,在elementUI封装成组件(在PC端)
//使用方式:
...
<upload-cover-item :url="form.url"
@change="changeAvatar" />
...
// 图片
changeAvatar (data) {
this.form.url= data
},
//upload-cover-item
<template>
<div class="upload-box">
<div class="avatar-uploader-box">
<!-- 方框样式 -->
<el-upload ref="avatarUploader"
class="avatar-uploader"
:action="actionUrl"
:show-file-list="false"
:on-change="handleAvatarChange"
:auto-upload="false"
accept="image/*"
v-if="type==='avatar' && !imageUrl">
<span v-loading="loading"
element-loading-text="上传中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
style="line-height:30px;"
v-if="!imageUrl">
<i class="el-icon-plus avatar-uploader-icon"></i></span>
</el-upload>
<!-- 上传的图片 -->
<img v-if="imageUrl"
v-lazy="imageUrl"
:src="imageUrl"
class="avatar"
@mouseover.stop="isShowPopup = true" />
<!-- 显示查看和删除的按钮弹窗 -->
<div class="avatar-uploader-popup"
v-show="imageUrl && isShowPopup"
@mouseleave="isShowPopup = false">
<i class="el-icon-zoom-in"
@click="dialogVisible = true"></i>
<i class="el-icon-delete"
@click="delImageUrl"></i>
</div>
</div>
<!-- 查看大图 -->
<el-dialog title="图片查看"
center
:visible.sync="dialogVisible"
append-to-body>
<img width="100%"
:src="imageUrl"
alt />
</el-dialog>
<!-- 裁剪图片 start-->
<vue-cropper-item ref="VueCropperItem"
@confirm="confirmCropper" />
<!-- 裁剪图片 end-->
</div>
</template>
<script>
import * as url from '@/api/httpConfig'
import { uploadOss } from '@/api/modules/system'
// 上传图片 export const uploadOss = params => http.upload(`/sys/oss/upload`, params)
export default {
name: 'upload-item',
components: {
VueCropper,
},
props: {
type: {
type: String,
default: 'avatar'
},
url: {
type: String,
default: ''
},
autoCropWidth: {
type: Number,
default: 275
},
autoCropHeight: {
type: Number,
default: 206
},
fixedBox: {
type: Boolean,
default: false
},
isCompress: { //是否压缩
type: Boolean,
default: true
},
compress: { //压缩率
type: String,
default: '0.8'
},
},
data () {
return {
loading: false,
isShowPopup: false,
dialogVisible: false,
isProgress: false,
percentage: 0,
imageUrl: '',
actionUrl: `${url.default.apiURL}/sys/oss/upload`,
}
},
created () {
this.imageUrl = this.url;
},
methods: {
// 上传之前
beforeAvatarUpload (file) {
return new Promise((resolve, reject) => {
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(file.name)) {
return reject('上传图片只能是JPG或PNG格式!');
}
if (file.size > 5 * 1024 * 1024) {
return reject('上传图片大小不能超过5M!');
}
resolve("符合表單規則");
});
},
// 上传改变
async handleAvatarChange (file, fileList) {
try {
await this.beforeAvatarUpload(file)
// console.log('上传改变', file)
this.showVueCropperItem(file)
} catch (e) {
this.$message.warning(JSON.stringify(e))
}
},
// 上传图片接口
async uploadOssApi (data) {
try {
let params = new FormData()
params.append('file', data)
const res = await uploadOss(params)
this.imageUrl = res.data.url;
this.isProgress = false
this.$emit('change', res.data.url)
} catch (err) {
this.$message.error('上传失败')
this.imageUrl = ''
this.isProgress = false
this.$emit('change', '')
}
},
// 删除图片
delImageUrl () {
this.imageUrl = ''
this.$emit('change', '')
},
// 显示裁剪框
showVueCropperItem (file) {
this.$refs.VueCropperItem.init()
this.$refs.VueCropperItem.fileName = file.name;
this.$refs.VueCropperItem.options.img = URL.createObjectURL(file.raw);
this.setVueCropperOptions()
},
// 确认裁剪后上传
async confirmCropper (file) {
this.loading = true
await this.uploadOssApi(file)
this.loading = false
},
// 设置裁剪的配置
setVueCropperOptions () {
this.$refs.VueCropperItem.options.autoCropWidth = this.autoCropWidth;
this.$refs.VueCropperItem.options.autoCropHeight = this.autoCropHeight;
this.$refs.VueCropperItem.options.fixedBox = this.fixedBox;
this.$refs.VueCropperItem.isCompress = this.isCompress; //是否压缩图片
this.$refs.VueCropperItem.compress = this.compress //压缩率
},
},
watch: {
url () {
this.imageUrl = this.url;
}
}
}
</script>
<style lang="scss" scoped>
.upload-box {
.avatar-uploader-box {
position: relative;
line-height: 0;
width: fit-content; // 收缩与包裹,收缩到合适
max-width: 400px;
.avatar-uploader {
/deep/ .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
&:hover {
border-color: #409eff;
}
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
min-width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
min-width: 178px;
display: block;
}
}
.progress-box {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 99%;
height: 99%;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.avatar-uploader-popup {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 100%;
height: 100%;
background: rgba($color: #000000, $alpha: 0.5);
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 20px;
border-radius: 6px;
i {
width: 30%;
text-align: center;
padding: 0 5%;
font-size: 24px;
}
}
}
}
</style>
//vue-cropper-item
<template>
<!-- 裁剪图片 start-->
<el-dialog title="裁剪图片"
width="700px"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
:append-to-body="true"
:visible.sync="isShowCropper">
<!-- 主区域 start -->
<div class="vue-cropper-box">
<!-- 裁剪框 start -->
<div class="vue-cropper-content">
<div class="show-cropper"
v-loading="loading"
element-loading-text="加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)">
<VueCropper ref="cropper"
:img="options.img"
:outputSize="options.size"
:outputType="options.outputType"
:info="options.info"
:centerBox="options.centerBox"
:canScale="options.canScale"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:fixed="options.fixed"
:fixedNumber="options.fixedNumber"
:original="options.original"
:full="options.full"
@realTime="realTime"
@imgLoad="imgLoad"></VueCropper>
</div>
</div>
<!-- 裁剪框 end -->
<!--底部 设置按钮 start-->
<div class="vue-cropper-bottom">
<p class="vue-cropper-bottom-item">
自定义尺寸:<el-switch v-model="options.fixedBox"
active-color="#13ce66"
inactive-color="#ff4949"
:active-value="false"
:inactive-value="true"> </el-switch>
</p>
<p class="vue-cropper-bottom-item">
<el-tooltip class="item"
effect="dark"
content="放大图片"
placement="bottom">
<i class="el-icon-zoom-in scale"
@click="changeScale(1)"></i>
</el-tooltip>
</p>
<p class="vue-cropper-bottom-item">
<el-tooltip class="item"
effect="dark"
content="缩小图片"
placement="bottom">
<i class="el-icon-zoom-out scale"
@click="changeScale(-1)"></i>
</el-tooltip>
</p>
<p class="vue-cropper-bottom-item">
<el-tooltip class="item"
effect="dark"
content="向左旋转90°"
placement="bottom">
<i class="el-icon-refresh-left scale"
@click="rotateLeft"></i>
</el-tooltip>
</p>
</div>
<!--底部 设置按钮 end-->
</div>
<!-- 主区域 end -->
<span slot="footer"
class="dialog-footer">
<el-button v-if="isShowCropper"
@click="cancelCubeImg">取消</el-button>
<el-button v-if="isShowCropper"
type="danger"
:disabled="loading"
:loading="isLoading"
@click="onCubeImg">确定</el-button>
</span>
</el-dialog>
<!-- 裁剪图片 end-->
</template>
<script>
import { VueCropper } from "vue-cropper"
export default {
name: 'vue-cropper-item',
components: {
VueCropper,
},
data () {
return {
isCompress: true, //是否压缩
compress: 0.8, //压缩率
isShowCropper: false,
options: {
img: '',
info: true,
size: 1,
outputType: 'jpeg', //裁剪生成图片的格式
centerBox: true, //截图框是否被限制在图片里面
canScale: true, //图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框, 只有自动截图开启 宽度高度才生效
autoCropWidth: 320,
autoCropHeight: 200,
fixedBox: false, // 固定截图框大小 不允许改变
fixed: false, // 开启宽度和高度比例
fixedNumber: [4, 4],
original: false, // 上传图片按照原始比例渲染
full: true // 是否输出原图比例的截图
},
fileName: null,
loading: false,
isLoading: false,
previews: {},
}
},
methods: {
// 初始化
init () {
this.isShowCropper = true
this.loading = true
},
// 图片加载完成
imgLoad (data) {
this.loading = false
this.isLoading = false
},
// 裁剪图放大或缩小
changeScale (val) {
this.$refs.cropper.changeScale(val)
},
// 向左旋转
rotateLeft () {
this.$refs.cropper.rotateLeft()
},
// 裁剪图片上传
onCubeImg (file) {
this.isLoading = true
this.$refs.cropper.getCropData(data => {
this.isLoading = false
this.isShowCropper = false
this.options.img = ''
let file = null
if (this.isCompress) { //是否压缩
let img = new Image()
img.src = data
img.onload = () => {
let _data = this.onImgCompression(img)
file = this.dataURLtoFile(_data, this.fileName)
console.log('图片大小-压缩过:', (file.size / 1024).toFixed(2), 'kb,', '压缩率:', this.compress)
this.$emit('confirm', file)
}
} else {
file = this.dataURLtoFile(data, this.fileName)
console.log('图片大小-未压缩:', (file.size / 1024).toFixed(2), 'kb')
this.$emit('confirm', file)
}
})
},
// 将裁剪base64的图片转换为file文件
dataURLtoFile (dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
},
// 压缩图片
onImgCompression (img) {
let canvas = document.createElement("canvas")
let ctx = canvas.getContext("2d")
let initSize = img.src.length
let width = img.width
let height = img.height
canvas.width = width
canvas.height = height
// 铺底色
ctx.fillStyle = "#fff"
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, width, height)
//进行压缩
let compress = this.compress || 0.8 //压缩率
return canvas.toDataURL("image/jpeg", compress)
},
// 取消裁剪
cancelCubeImg () {
this.isShowCropper = false
this.$message.info('取消裁剪图片!')
},
},
watch: {
}
}
</script>
<style lang="scss" scoped>
.vue-cropper-box {
width: 100%;
height: 450px;
.vue-cropper-content {
width: 100%;
height: 90%;
padding-bottom: 20px;
text-align: center;
display: flex;
justify-content: space-between;
.show-cropper {
// width: 50%;
width: 100%;
height: 100%;
}
.show-preview {
width: 50%;
height: 100%;
margin: 5px;
overflow: hidden;
}
}
.vue-cropper-bottom {
display: flex;
flex-flow: wrap row;
// justify-content: space-between;
align-items: center;
&-item {
margin-right: 15px;
}
.scale {
font-size: 24px;
color: dodgerblue;
vertical-align: middle;
&:hover {
color: mediumseagreen;
box-shadow: 0 0 2px 1px rgba(0, 140, 186, 0.5);
}
}
}
}
</style>
2019-11-07最新更新,在Vant封装成组件 (移动端)
//使用方式:
...
<upload-cover-item :url="form.url"
@change="changeAvatar" />
...
// 图片
changeAvatar (data) {
this.form.url= data
},
//upload-cover-item
<template>
<div class="upload-box">
<div class="avatar-uploader-box">
<van-uploader :before-read="beforeRead"
v-if="!imageUrl">
<!-- 背景图,可更换 -->
<img src="../../assets/img/common/product-cover-upload.png" />
</van-uploader>
<!-- 上传后的图片显示 -->
<div class="avatar-img-box"
v-if="imageUrl">
<img v-lazy="imageUrl"
:src="imageUrl"
class="avatar-img"
@click="openPreview" />
<van-icon name="clear"
class="delete-icon"
@click="delImageUrl" />
</div>
</div>
<!-- 预览图片 -->
<van-image-preview v-model="isShowPreview"
:images="previewImgs">
<template v-slot:index>预览图片</template>
</van-image-preview>
<!-- 裁剪图片 -->
<vue-cropper-item ref="VueCropperItem"
@confirm="confirmCropper" />
</div>
</template>
<script>
import { uploadOss } from '@/api/index'
// 上传图片 export const uploadOss = params => http.upload(`/sys/oss/upload`, params)
export default {
name: 'upload-item',
props: {
type: {
type: String,
default: 'avatar'
},
url: {
type: String,
default: ''
},
autoCropWidth: {
type: Number,
default: 275
},
autoCropHeight: {
type: Number,
default: 206
},
fixedBox: {
type: Boolean,
default: false
},
isCompress: { //是否压缩
type: Boolean,
default: true
},
compress: { //压缩率
type: String,
default: '0.8'
},
},
data () {
return {
isShowPreview: false,
imageUrl: '', //require('../../assets/img/logo.png'),
previewImgs: []
}
},
created () {
this.imageUrl = this.url;
},
methods: {
// 预览图片
openPreview () {
this.isShowPreview = true;
this.previewImgs[0] = this.imageUrl
},
// 上传之前
beforeRead (file) {
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(file.name)) {
return this.$toast('上传图片只能是JPG或PNG格式!');
}
if (file.size > 5 * 1024 * 1024) {
return this.$toast('上传图片大小不能超过5M!');
}
// console.log('选择完成显示裁剪框', file)
this.showVueCropperItem(file)
},
// 显示裁剪框
showVueCropperItem (file) {
this.$refs.VueCropperItem.init()
this.$refs.VueCropperItem.fileName = file.name;
this.$refs.VueCropperItem.options.img = URL.createObjectURL(file);
this.setVueCropperOptions()
},
// 设置裁剪的配置
setVueCropperOptions () {
this.$refs.VueCropperItem.options.autoCropWidth = this.autoCropWidth;
this.$refs.VueCropperItem.options.autoCropHeight = this.autoCropHeight;
this.$refs.VueCropperItem.options.fixedBox = this.fixedBox;
this.$refs.VueCropperItem.isCompress = this.isCompress; //是否压缩图片
this.$refs.VueCropperItem.compress = this.compress //压缩率
},
// 确认裁剪后上传
async confirmCropper (file) {
await this.uploadOssApi(file)
},
// 上传图片接口
async uploadOssApi (data) {
this.$showLoading('上传中...');
try {
let params = new FormData()
params.append('file', data)
const res = await uploadOss(params)
this.imageUrl = res.data.url;
this.$emit('change', res.data.url)
} catch (err) {
this.$toast.fail('上传失败')
this.imageUrl = ''
this.$emit('change', '')
}
this.$toast.clear()
},
// 删除图片
delImageUrl () {
this.imageUrl = ''
this.$emit('change', '')
}
},
watch: {
url () {
this.imageUrl = this.url;
}
}
}
</script>
<style lang="scss" scoped>
.upload-box {
/deep/ .van-uploader__wrapper {
width: 80px;
height: 60px;
background: #f3f3f5;
border: 1px solid #e1e1e3;
border-radius: 8px;
display: flex;
justify-content: center;
}
.avatar-img-box {
position: relative;
width: 80px;
height: 60px;
border: 1px solid #f3f3f5;
border-radius: 8px;
.avatar-img {
width: 100%;
height: 100%;
overflow: hidden;
}
.delete-icon {
position: absolute;
top: -10px;
right: -10px;
font-size: 22px;
}
}
}
</style>
//vue-cropper-item
<template>
<!-- 裁剪图片 start-->
<div class="vue-cropper-container"
v-if="isShowCropper">
<header class="header-nav">裁剪图片</header>
<!-- 主区域 start -->
<div class="vue-cropper-box">
<!-- 裁剪框 start -->
<div class="vue-cropper-content">
<div class="show-cropper">
<VueCropper ref="cropper"
:img="options.img"
:outputSize="options.size"
:outputType="options.outputType"
:info="options.info"
:centerBox="options.centerBox"
:canScale="options.canScale"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:fixed="options.fixed"
:fixedNumber="options.fixedNumber"
:original="options.original"
:full="options.full"
@imgLoad="imgLoad"></VueCropper>
</div>
</div>
<!-- 裁剪框 end -->
</div>
<!-- 主区域 end -->
<div class="vue-cropper-footer">
<span @click="cancelCubeImg">{{$t('btn.cancel')}}</span>
<span @click="onCubeImg">{{$t('btn.confirm')}}</span>
</div>
</div>
<!-- 裁剪图片 end-->
</template>
<script>
import { VueCropper } from "vue-cropper"
export default {
name: 'vue-cropper-item',
components: {
VueCropper,
},
data () {
return {
isCompress: true, //是否压缩
compress: 0.8, //压缩率
isShowCropper: false,
options: {
img: require('../../assets/img/logo.png'),
info: true,
size: 1,
outputType: 'jpeg', //裁剪生成图片的格式
centerBox: true, //截图框是否被限制在图片里面
canScale: true, //图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框, 只有自动截图开启 宽度高度才生效
autoCropWidth: 275,
autoCropHeight: 206,
fixedBox: true, // 固定截图框大小 不允许改变
fixed: false, // 开启宽度和高度比例
fixedNumber: [4, 4],
original: false, // 上传图片按照原始比例渲染
full: true // 是否输出原图比例的截图
},
fileName: null,
}
},
methods: {
// 初始化
init () {
this.isShowCropper = true
this.$showLoading(this.$t('loading'));
},
// 图片加载完成
imgLoad (data) {
this.$toast.clear()
},
// 裁剪图片上传
onCubeImg (file) {
if (!this.isShowCropper) return
this.$showLoading(this.$t('confirm'));
this.$refs.cropper.getCropData(data => {
this.$toast.clear()
this.isShowCropper = false
this.options.img = ''
let file = null
if (this.isCompress) { //是否压缩
let img = new Image()
img.src = data
img.onload = () => {
let _data = this.onImgCompression(img)
file = this.dataURLtoFile(_data, this.fileName)
console.log('图片大小-压缩过:', (file.size / 1024).toFixed(2), 'kb,', '压缩率:', this.compress)
this.$emit('confirm', file)
}
} else {
file = this.dataURLtoFile(data, this.fileName)
console.log('图片大小-未压缩:', (file.size / 1024).toFixed(2), 'kb')
this.$emit('confirm', file)
}
})
},
// 将裁剪base64的图片转换为file文件
dataURLtoFile (dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
},
// 压缩图片
onImgCompression (img) {
let canvas = document.createElement("canvas")
let ctx = canvas.getContext("2d")
let initSize = img.src.length
let width = img.width
let height = img.height
canvas.width = width
canvas.height = height
// 铺底色
ctx.fillStyle = "#fff"
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, width, height)
//进行压缩
let compress = this.compress || 0.8 //压缩率
return canvas.toDataURL("image/jpeg", compress)
},
// 取消裁剪
cancelCubeImg () {
this.isShowCropper = false
this.$toast(this.$t('tips.cancelText'))
}
},
watch: {
}
}
</script>
<style lang="scss" scoped>
.vue-cropper-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
width: 100%;
height: 100%;
background: #000;
.vue-cropper-box {
width: 100%;
height: 70%;
margin: 10% 0;
.vue-cropper-content {
width: 100%;
height: 90%;
padding-bottom: 20px;
text-align: center;
display: flex;
justify-content: space-between;
.show-cropper {
width: 100%;
height: 100%;
}
}
}
}
.header-nav {
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
color: #fff;
font-size: 16px;
}
.vue-cropper-footer {
position: absolute;
bottom: 0;
width: 100%;
height: 50px;
line-height: 40px;
text-align: center;
padding: 5px 0;
color: #fff;
border-top: 1px solid rgba(255, 255, 255, 0.4);
span {
width: 50%;
&:first-child {
border-right: 1px solid rgba(255, 255, 255, 0.4);
}
}
}
</style>