vue-cropperjs 插件的组件化使用 前端裁剪插件 vue
vue-cropperjs 插件的组件化使用
安装
npm install --save vue-cropperjs 或者 cnpm install --save vue-cropperjs
局部引入
import VueCropper from 'vue-cropperjs'
export default {
components: { VueCropper },
组件内容
<div>
<div class="crop-demo">
<div class="crop-demo-btn" v-show="false">
点击更换图片
<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" id="change" />
</div>
</div>
<el-dialog :append-to-body="true" title="图片剪裁" :visible.sync="dialogVisible" :close-on-click-modal="false" width="40%">
<vue-cropper :aspect-ratio="cropperAspectWH" ref="cropper" :src="imgSrc" :ready="cropImage" :zoom="cropImage" :cropmove="cropImage" style="width: 100%; height: 300px"></vue-cropper>
<span slot="footer" class="dialog-footer">
<el-button @click="cancelCrop">取 消</el-button>
<el-button type="primary" @click="upladPic">确 定</el-button>
</span>
</el-dialog>
<div v-show="false">{{ thisAspectWH }}</div>
</div>
</template>
<script>
import VueCropper from 'vue-cropperjs'
export default {
components: { VueCropper },
props: ['label', 'AspectWH'],//label 是父组件传的标识符 (用于一个页面内多处使用裁剪组件,裁剪结果返回值错乱) AspectWH 是用于限定裁剪框的比例的1为1:1 可传null则是不限制(注意传值是否为字符串)
data() {
return {
//以下都是截图插件的
imgSrc: '',
dialogVisible: false,
img_size: '',
max_fuyuan_defaultSrc: [],
cropperAspectWH: 1, //图片剪裁宽高比例
reader: '',
e_photo_file: '',
e_photo_filefile: '',
http_cropImg: '', //带http
cropImg: '', //默认图片不带http
}
},
methods: {
//监听父组件是否点击上传的事件
childAction() {
$('#change').click()
},
//向父组件发送数据 cropImg 裁剪得到的图片名称 http_cropImg 带域名的图片名称 label就是传进来的标识符,也带着传出去
sendMsg() {
this.$emit('getPicNamefile', this.cropImg, this.http_cropImg, this.label)
},
/******************************图片剪切开始****************************************/
setImage(e) {
let that = this
this.e_photo_file = e
let file = e.target.files[0]
this.e_photo_filefile = file
if (!file.type.includes('image/')) {
return
}
this.reader = ''
let canvas = '',
ctx = '',
img = ''
this.imgSrc = ''
this.reader = new FileReader()
this.reader.onload = (event) => {
if (file.size >= 1024 * 1024 * this.GLOBAL.fileSize) {
//调用自定义方法来处理图片
var quality = 1 //压缩图片的质量
canvas = document.createElement('canvas') //创建画布
ctx = canvas.getContext('2d')
img = new Image()
img.src = event.target.result
img.onload = function () {
const width = img.width
const height = img.height
canvas.width = 1200 //这里可以自定义你的图片大小
canvas.height = 1200 * (img.height / img.width)
that.dialogVisible = true
setTimeout(() => {
ctx.fillRect(0, 0, 0, 0)
ctx.drawImage(img, 0, 0, 1200, canvas.height)
that.imgSrc = canvas.toDataURL('image/jpeg', quality) //将图片转为Base64 之后预览要用
that.$refs.cropper.replace(that.imgSrc)
}, 50)
}
} else {
that.dialogVisible = true
that.$nextTick(function () {
that.imgSrc = event.target.result
that.$refs.cropper.replace(event.target.result)
})
}
}
that.reader.readAsDataURL(file)
},
setImage_two(e) {
let that = this
let file = this.e_photo_filefile
let canvas = '', ctx = '',img = '';
this.e_photo_file = e
this.e_photo_filefile = file
this.reader = ''
this.imgSrc = ''
this.reader = new FileReader()
this.reader.onload = (event) => {
//调用自定义方法来处理图片
var quality = 1 //压缩图片的质量
canvas = document.createElement('canvas') //创建画布
ctx = canvas.getContext('2d')
img = new Image()
img.src = event.target.result
img.onload = function () {
// 清除画布
const width = img.width
const height = img.height
canvas.width = 1200 //这里可以自定义你的图片大小
canvas.height = 1200 * (img.height / img.width)
setTimeout(() => {
ctx.fillRect(0, 0, 0, 0)
ctx.drawImage(img, 0, 0, 1200, canvas.height)
that.imgSrc = canvas.toDataURL('image/jpeg', quality) //将图片转为Base64 之后预览要用
that.$refs.cropper && that.$refs.cropper.replace(that.imgSrc)
}, 50)
}
}
that.reader.readAsDataURL(file)
},
cropImage() {
this.http_cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL()
},
cancelCrop() {
this.dialogVisible = false
this.http_cropImg = this.max_fuyuan_defaultSrc[this.max_fuyuan_defaultSrc.length - 1]
$('#change').val('') //取消change事件
},
upladPic() {
this.sumitImageFile(this.http_cropImg)
},
sumitImageFile(base64Codes) {
let that = this
var formData = new FormData()
var picName = new Date().getTime() + '.png' //给截图的文件命名
formData.append('file', that.convertBase64UrlToBlob(base64Codes), picName) //append函数的第一个参数是后台获取数据的参数名,和html标签的input的name属性功能相同
if (this.img_size >= 1024 * 1024 * this.GLOBAL.fileSize) {
this.$message({
message: '要上传图片太大,请再次截取,本次截取将进行压缩处理!',
type: 'warning',
})
this.setImage_two(that.e_photo_file)
return
}
if (this.img_size / 1024 / 1024 < this.GLOBAL.fileSize) {
serviceApi.requestPostUploadFile(formData).then((body) => {
that.cropImg = body.file_name
//传递给父组件
that.sendMsg()
})
} else {
this.$message({
message: '抱歉,要上传图片太大,请重新上传!',
type: 'warning',
})
that.cropImg = ''
that.http_cropImg = ''
//传给表单
//传递给父组件
that.cropper_show = false
that.sendMsg()
}
//关闭弹框
$('#change').val('') //取消change事件
this.dialogVisible = false
},
//将以base64的图片url数据转换为Blob
convertBase64UrlToBlob(urlData) {
var bytes = window.atob(urlData.split(',')[1]) //去掉url的头,并转换为byte
//处理异常,将ascii码小于0的转换为大于0
var ab = new ArrayBuffer(bytes.length)
var ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i)
}
let size = new Blob([ab], { type: 'image/png' })
this.img_size = size.size
return new Blob([ab], { type: 'image/png' })
},
/******************************图片剪切结束****************************************/
},
computed: {
thisAspectWH() {
if (this.AspectWH) {
this.cropperAspectWH = this.AspectWH
}
},
},
mounted() {
//监听父组件是否点击上传的事件
this.$on('inputfile', (val) => {
if (this.AspectWH) {
this.cropperAspectWH = this.AspectWH
}
this.childAction(val)
})
},
watch: {},
created() {
if (this.AspectWH) {
this.cropperAspectWH = this.AspectWH
}
},
}
</script>
<style scoped>
/* 图片剪裁样式 */
.crop-demo {
display: flex;
align-items: flex-end;
width: 150px;
height: 150px;
}
.crop-demo-btn {
position: absolute;
left: auto;
top: 50%;
transform: translateY(-50%);
width: 100px;
height: 40px;
line-height: 40px;
padding: 0;
text-align: center;
font-size: 12px;
margin-left: 25px;
color: #fff;
background-color: rgba(0, 0, 0, 0.2);
border-radius: 4px;
box-sizing: border-box;
cursor: pointer;
}
.crop-input {
position: absolute;
width: 100px;
height: 40px;
left: 0;
top: 0;
opacity: 0;
font-size: 0;
padding: 0;
cursor: pointer;
}
</style>
注意点
这个方法要自己写 serviceApi.requestPostUploadFile
父组件中使用
<div class="crop-demo">
<div
style="
position: relative;
display: flex;
width: 340px;
height: 170px;
"
>
<span>
<img
:src="XXXXXXX"
style="
width: 340px;
height: 170px;
background: #f8f8f8;
border: 1px solid #eee;
border-radius: 5px;
object-fit: cover;
"
/>
</span>
<div
style="
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100px;
line-height: 40px;
padding: 0;
text-align: center;
font-size: 12px;
background-color: #9da1a585;
color: #fff;
border-radius: 4px;
box-sizing: border-box;
"
>
点击更换图片
<div
@click="toSonClick('label')"
style="
position: absolute;
width: 100px;
height: 40px;
left: 0;
top: 0;
opacity: 0;
cursor: pointer;
"
/>
</div>
</div>
</div>
<CropperCut
v-if="CropperCutShow"
:AspectWH="AspectWH"
:label="CropperCutlabel"
@getPicNamefile="getPicNamefile"
ref="CropperCut"
></CropperCut>
data中加入:
//裁剪插件的label 是谁调用的
AspectWH: "1", //裁剪插件的宽高比
CropperCutlabel: "",
CropperCutShow: false, //控制开关 裁剪插件
//裁剪插件的事件
toSonClick(label) {
let that = this;
if (label == "label") {
this.AspectWH = 1;
} else if (label == "XXX") {
this.AspectWH = 2;
}
this.CropperCutShow = true;
this.CropperCutlabel = label;
setTimeout(() => {
that.$refs.CropperCut.$emit("inputfile");
}, 10);
},
//插件插件
getPicNamefile(cropImg, http_cropImg, label) {
this.CropperCutShow = false;
this.AspectWH = 1;
if (label == "label") {
this.CropperCutlabel = "";
} else if (label == "XXX") {
this.CropperCutlabel = "";
}
},