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 = "";
}
},