在现代Web应用中,图片处理是一个常见的需求。本文将介绍如何使用Vue.js结合Cropper.js实现一个简单的图片裁剪功能。以下是实现该功能的完整代码。
代码实现
<template>
<div class="c-copper-container" :class="{'wd260' : type == 'articlesubmit'}">
<div class="c-copper-box">
<div class="c-image-box">
<img :src="copperImgUrl" id="image" alt="暂无图片">
</div>
<div class="c-preview-box">
<div class="img-preview">
<div class="title">预览</div>
<div class="preview"><img :src="copperImgUrl" alt="暂无图片"></div>
</div>
<div class="img-upload-btn">
<el-button icon="cs-format-image" size="mini" plain>上传图片</el-button>
<input type="file" accept="image/png,image/jpeg,image/jpg" id="imgFile" @change="getFile">
</div>
</div>
</div>
<div class="c-btn-group">
<el-button type="info" plain @click="cancel">取消</el-button>
<el-button type="primary" @click="getCropperImg">确定</el-button>
</div>
</div>
</template>
代码解析
-
<div class="c-copper-container" :class="{'wd260' : type == 'articlesubmit'}">
:- 定义了一个容器,并根据
type
属性动态添加wd260
类。
- 定义了一个容器,并根据
-
<div class="c-copper-box">
:- 包含图片裁剪和预览的主要布局。
-
<div class="c-image-box">
:- 裁剪图片显示区域。
-
<img :src="copperImgUrl" id="image" alt="暂无图片">
:- 绑定了一个图片标签,用于显示裁剪的图片。
-
<div class="c-preview-box">
:- 图片预览区域。
-
<div class="img-preview">
:- 包含预览标题和预览图片。
-
<el-button icon="cs-format-image" size="mini" plain>上传图片</el-button>
:- 上传图片按钮。
-
<input type="file" accept="image/png,image/jpeg,image/jpg" id="imgFile" @change="getFile">
:- 文件输入框,监听文件变化事件
getFile
。
- 文件输入框,监听文件变化事件
-
<el-button type="info" plain @click="cancel">取消</el-button>
:- 取消按钮,触发
cancel
方法。
- 取消按钮,触发
-
<el-button type="primary" @click="getCropperImg">确定</el-button>
:- 确定按钮,触发
getCropperImg
方法。
- 确定按钮,触发
JavaScript 部分
<script>
import { dataURItoBlob } from '@/utils'
export default {
name: 'CropperImage',
data () {
return {
copperImgUrl: '', // 被剪裁的图片地址
option: {
viewMode: 1, // 裁剪框只能图片内部移动
dragMode: 'move', // 裁剪框只可以移动,不可以新建
aspectRatio: 1, // 裁剪框比例
preview: '.preview', // 预览的dom节点
checkCrossOrigin: false, // 不检查跨域图像
movable: false, // 设置图片可不移动
rotatable: false, // 设置图片不可旋转
scalable: false, // 设置图片不可缩放
zoomable: false, // 设置图片不可放大
zoomOnTouch: false, // 设置图片不可被拖动触摸放大
toggleDragModeOnDblclick: true, // 点击两次时可以在“crop”和“move”之间切换拖拽模式
minCropBoxWidth: '5', // 裁剪层最小宽度
minCropBoxHeight: '5' // 裁剪层最小高度
}
}
},
props: {
cropperOption: {
type: Object,
default: () => {
return null
}
},
fileSize: {
type: Number,
default: 0.8
},
fileType: {
type: String,
default: 'jpeg'
},
imageFile: {},
sizeNum:{
type: Number,
default: 0
},
type:{
type: String,
default: ''
}
},
watch: {
imageFile (file) {
this.fileHandle(file)
}
},
methods: {
initCropperModel () {
if (this.cropperOption) {
for (let key in this.option) {
this.option[key] = this.cropperOption[key] || this.option[key]
}
}
let $image = document.getElementById('image')
this.cropper = new Cropper($image, this.option)
},
getFile (e) {
let file = e.target.files[0]
let _sizeNum = this.sizeNum
if(_sizeNum){
const isLtSize = file.size / 1024 / 1024 < _sizeNum
if (!isLtSize) {
this.$message({
message: this.type == 'articlesubmit' ? `图片大小不能超过 ${_sizeNum}M!` : `图片大小不能超过 ${_sizeNum * 1000}kb!`,
type: 'error'
})
e.target.value = ''
return false
}
}
this.fileHandle(file)
},
fileHandle (file) {
if (!file) return
if (!window.FileReader) return
let vm = this
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onloadend = function () {
vm.copperImgUrl = this.result
vm.resetCropperImg()
}
},
resetCropperImg () {
this.cropper.reset()
this.cropper.replace(this.copperImgUrl)
},
getCropperImg () {
let canvas = this.cropper.getCroppedCanvas();
if (this.fileType === 'image/png') {
let ctx = canvas.getContext('2d');
ctx.fillStyle = "rgba(0,0,0,0)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
let newImageData = canvas.toDataURL('image/png');
let blob = dataURItoBlob(newImageData);
let formData = new FormData();
formData.append('icon', blob);
this.$emit('cropped', newImageData, formData);
},
cancel () {
this.$emit('cancel')
}
},
created () {
this.fileHandle(this.imageFile)
},
mounted () {
this.initCropperModel()
},
beforeDestroy () {
this.copperImgUrl = ''
this.cropper.destroy()
}
}
</script>
代码解析
-
data ()
:- 定义组件的数据属性,包括图片URL和裁剪器的配置项。
-
props
:- 定义父组件传入的属性,包括裁剪配置、文件大小和类型等。
-
watch
:- 监听
imageFile
的变化,当文件变化时调用fileHandle
方法。
- 监听
-
methods
:initCropperModel ()
:初始化 Cropper.js 实例。getFile (e)
:获取上传的文件并处理。fileHandle (file)
:处理上传的文件,将文件转换为Base64格式。resetCropperImg ()
:重置裁剪器的图片。getCropperImg ()
:获取裁剪后的图片,并将其转换为Blob格式。cancel ()
:取消操作。
-
created ()
:- 在组件创建时处理初始图片文件。
-
mounted ()
:- 在组件挂载时初始化裁剪器。
-
beforeDestroy ()
:- 在组件销毁前清理裁剪器实例。
样式部分
<style scoped lang="stylus" rel="stylesheet">
.c-copper-container {
width 450px
font-size 12px
margin-top 20px
&.wd260{
width 260px
.img-upload-btn .el-button{
padding 7px 5px
}
.c-image-box {
width 188px
height 188px
& img {
max-width 100%
}
>>> .cropper-bg{
width 200px !important
}
}
.c-preview-box {
width 80px
.img-preview {
padding 5px 8px
height 100px
}
.preview {
width 60px
height 60px
}
}
}
.c-copper-box {
display flex
}
.c-image-box {
width 250px
height 250px
margin-right 20px
background #868686
& img {
max-width 100%
}
}
.c-preview-box {
width 180px
text-align center
.img-preview {
width 100%
padding 10px 15px
height 200px
box-sizing border-box
border 1px solid #e8e8e8
background #fafafa
}
.title {
padding-bottom 5px
}
.preview {
width 148px
height 148px
overflow hidden
background-color #fff
border 1px solid #e8e8e8
display inline-block
}
}
.img-upload-btn {
position relative
margin-top 18px
&:hover .el-button {
color #168FCA
border-color #168FCA
transition all .1s
}
& /deep/ i, & /deep/ span {
display inline-block
vertical-align middle
}
.el-button {
width 100%
border-radius 0
}
#imgFile {
position absolute
width 100%
height 100%
top 0
left 0
opacity 0
cursor pointer
}
}
.c-btn-group {
padding-top 20px
text-align center
.el-button {
width 100px
}
}
}
</style>
代码解析
-
定义了组件的样式,包括容器宽度、字体大小等。
-
使用了
scoped
属性,确保样式仅应用于当前组件。 -
采用了Stylus语法编写样式,提高了代码的可读性和易维护性。
总结
通过以上代码,我们实现了一个基于Vue.js和Cropper.js的图片裁剪组件,用户可以上传图片并进行裁剪操作,最终获取裁剪后的图片数据。这个组件可以方便地集成到Vue.js应用中,为用户提供了良好的图片处理体验。