安裝vue-cropper
npm install vue-cropper
在.vue的文件中引入:
<template>
<div class="hello">
<div style="width:600px;height:600px;">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
: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"
:enlarge="option.enlarge"
@realTime="realTime"
@imgLoad="imgLoad"
@cropMoving="cropMoving"></vueCropper>
</div>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
name: 'HelloWorld',
components:{VueCropper},
data () {
return {
}
},
methods:{
}
}
</script>
在main.js中全局引入:
/*裁剪*/
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
封裝一個圖片增強的組件,可實現圖片的縮放、旋轉、裁剪等功能,效果如下:
調用組件的代碼:
<!--組件調用示例-->
<template>
<div>
<div style=" margin-left: 20px;margin-top: 20px; ">
<label>圖片上傳和圖片增強組件:</label>
<img-cropper-comp @childEvent="getImgBase64"></img-cropper-comp>
</div>
</div>
</template>
<script>
import ImgCropperComp from "../../components/imgcroppercompent/imgCropperComp";
export default {
name: 'home',
components: { ImgCropperComp },
data() {
return {
}
},
computed: {},
created() {
},
methods: {
//接受子組件傳遞的參數
getImgBase64(param) {
console.log('我是父組件base64:');
console.log(param);
this.img = param;
}
}
}
</script>
組件結構:
imgCropperComp.vue:
<!--選擇圖片加圖片裁剪-->
<template>
<div class="peerUpload" style="margin-top: 20px;margin-left: 20px">
<div class="upload">
<el-upload
class="self"
drag
action="test"
:auto-upload="false"
:on-change="onChange"
:show-file-list="false"
>
<div class="_uploadImg" v-if="showUploadImg">
<i class="el-icon-upload"></i>
<div class="el-upload__text"><em>支持拖拽、點擊上傳</em></div>
<div class="el-upload__tip" slot="tip">只能上傳jpg/png文件,且不超過500kb</div>
</div>
<img v-if="imageUrl" :src="imageUrl" style="width: 136px;height: 136px" class="avatar">
</el-upload>
<el-link v-if="imageUrl" type="primary" style="margin-left: 38px;" @click="cropImageDialog = true">圖片增強</el-link>
</div>
<!--圖片增強彈框組件-->
<dialog-cropper-comp :cropImageDialog="cropImageDialog" :fixedBox="fixedBox" :width="width" :imgFile="imageUrl" @childEvent="getChildValue"></dialog-cropper-comp>
</div>
</template>
<script>
import DialogCropperComp from "./dialogCropperComp";
export default {
name: "imgCropperComp",
components: {DialogCropperComp},
data() {
return {
showUploadImg: true,
imageUrl: '',
width: '43%',//增強圖片dialog寬度
fixedBox: false,//是否固定裁剪框
cropImageDialog: false//圖片增強dialog
}
},
methods:{
//獲取子組件傳遞的值
getChildValue(param) {
this.imageUrl = param;
this.cropImageDialog = false;
//獲得子組件的值並傳遞給父組件
this.sendParamToParent();
},
//向父組件傳值
sendParamToParent() {
// 調用父組件的方法並傳遞參數
this.$emit('childEvent', this.imageUrl)
},
//el-img
onChange(file, fileList) {
//blob類型
// this.imageUrl = URL.createObjectURL(file.raw);
this.showUploadImg = false;
//轉base64
let fr = new FileReader();
fr.readAsDataURL(file.raw);
fr.onload = e => {
this.imageUrl = e.target.result;
//值發生改變須向父組件傳值
this.sendParamToParent();
};
}
}
}
</script>
<style>
.self .el-upload-dragger {
width: 136px;
height: 136px;
}
.checkedClass .el-checkbox__label {
width: 55px;
}
.checkedClass {
margin-left: 12px;
}
</style>
<style lang="css" scoped>
.peerUpload {
display: flex;
}
.upload {
width: 136px;
height: 136px;
}
.uploadBefore p {
line-height: 28px;
color: #cccccc;
text-align: center;
font-size: 14px;
}
.uploadAfter {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
dialogCropperComp.vue:
<!--圖片增強彈框組件-->
<template>
<!--圖片裁剪-->
<div class="personal">
<!-- 上傳圖像前調整圖像的尺寸 -->
<el-dialog title="圖片增強" :visible.sync="cropImageDialog" class="cropImageForm" :width="width"
:close-on-click-modal="false" :show-close="false">
<div class="img-crop">
<!-- 1.截圖區域 -->
<div class="imgCrop-content">
<div class="cropper-content">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
:centerBox="option.centerBox"
@realTime="realTime"
@imgLoad="imgLoad"
></vueCropper>
</div>
<div class="preview-content">
<div class="show-preview">
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img" />
</div>
</div>
<p class="desc">預覽效果</p>
</div>
</div>
<!-- 2.操作按鈕區域 -->
<div class="btn-content">
<input class="btn" type="button" value="+" title="放大" @click="changeScale(1)" />
<input class="btn" type="button" style value="-" title="縮小" @click="changeScale(-1)" />
<input class="btn" type="button" value="↺" title="左旋轉" @click="rotateLeft" />
<input class="btn" type="button" value="↻" title="右旋轉" @click="rotateRight" />
<input class="btn" type="button" value="[]" title="框選" @click="changeLayer" />
<input v-if="false" class="btn" type="button" value="↓" title="下載" @click="down('blob')" />
</div>
</div>
<div class="btn-footer">
<el-button @click="sendParamToParent" size="small">關閉</el-button>
<el-button type="primary" @click="submitPhoto" size="small">確定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { VueCropper } from "vue-cropper";
export default {
name: "dialogCropperComp",
components: {
VueCropper
},
props: ['cropImageDialog', 'fixedBox','width','imgFile'],
data() {
return {
imageUrl: '',
//剪切圖片上傳
previews: {},
option: {
img: "",// 裁剪圖片的地址
outputSize: 1, //剪切後的圖片質量(0.1-1)
full: false, //輸出原圖比例截圖 props名full
outputType: "png",// 裁剪生成圖片的格式
canMove: true,
original: false,// 上傳圖片按照原始比例渲染
canMoveBox: true,// 截圖框能否拖動
autoCrop: false, // 是否默認生成截圖框
autoCropWidth: 150,
autoCropHeight: 150,
fixedBox: true,// 固定截圖框大小 不允許改變
info: true, // 裁剪框的大小信息
canScale: false, // 圖片是否允許滾輪縮放
fixed: true, // 是否開啓截圖框寬高固定比例
fixedNumber: [7, 5], // 截圖框的寬高比例
centerBox: true, // 截圖框是否被限制在圖片裏面
infoTrue: true // true 爲展示真實輸出圖片寬高 false 展示看到的截圖框寬高
},
}
},
watch: {
imgFile: {
handler(newImgFile, oldImgFile) {
this.option.img = newImgFile;
this.imageUrl = newImgFile;
},
immediate: true
},
fixedBox: {
handler(newValue, oldValue) {
this.option.fixedBox = newValue;
},
immediate: true
},
},
methods:{
sendParamToParent() {
// 調用父組件的方法並傳遞參數
this.$emit('childEvent', this.imageUrl)
},
// 上傳圖像
submitPhoto() {
// 獲取截圖的base64 數據
this.$refs.cropper.getCropData(data => {
this.imageUrl = data;
this.sendParamToParent();
//console.log("壓縮前的圖片大小:" + data.length)
// let img = new Image(),
// _this = this
// img.src = data
// img.onload = function() {
// // let _data = _this.compress(img)
// let blob = _this.dataURItoBlob(data)
// let formData = new FormData()
// formData.append("icon", blob)
// //console.log("將blob對象轉成formData對象:" + formData.get("icon"))
// }
});
// 獲取截圖的blob數據
// this.$refs.cropper.getCropBlob((data) => {
// // do something
// console.log(data)
// })
},
/*圖片操作欄開始*/
//放大/縮小
changeScale(num) {
num = num || 1;
this.$refs.cropper.changeScale(num);
},
//左旋轉
rotateLeft() {
this.$refs.cropper.rotateLeft();
},
//右旋轉
rotateRight() {
this.$refs.cropper.rotateRight();
},
changeLayer() {
this.option.autoCrop = !this.option.autoCrop;
if (!this.option.autoCrop) {
// this.$refs.cropper.startCrop() 開始截圖
// this.$refs.cropper.stopCrop() 停止截圖
this.$refs.cropper.clearCrop() //清除截圖
// this.$refs.cropper.changeScale() 修改圖片大小 正數爲變大 負數變小
// this.$refs.cropper.getImgAxis() 獲取圖片基於容器的座標點
// this.$refs.cropper.getCropAxis() 獲取截圖框基於容器的座標點
// this.$refs.cropper.goAutoCrop 自動生成截圖框函數
// this.$refs.cropper.rotateRight() 向右邊旋轉90度
// this.$refs.cropper.rotateLeft() 向左邊旋轉90度
}
},
// 實時預覽函數
realTime(data) {
this.previews = data;
},
//下載圖片
down(type) {
var aLink = document.createElement("a");
aLink.download = "author-img";
if (type === "blob") {
this.$refs.cropper.getCropBlob(data => {
aLink.href = window.URL.createObjectURL(data);
aLink.click();
});
} else {
this.$refs.cropper.getCropData(data => {
aLink.href = data;
aLink.click();
});
}
},
imgLoad(msg) {
console.log("imgLoad");
console.log(msg);
},
/*圖片操作欄結束*/
// 壓縮圖片
compress(img) {
let canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
initSize = img.src.length,
width = img.width,
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 ndata = canvas.toDataURL("image/jpeg", 0.8)
//console.log("壓縮後的圖片大小:" + ndata.length)
return ndata
},
// base64轉成bolb對象
dataURItoBlob(base64Data) {
let byteString
if (base64Data.split(",")[0].indexOf("base64") >= 0)
byteString = atob(base64Data.split(",")[1])
else
byteString = unescape(base64Data.split(",")[1])
let mimeString = base64Data .split(",")[0] .split(":")[1] .split(";")[0];
let ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString })
},
}
}
</script>
<style lang="less" >
.personal {
margin: 10px 0;
padding: 10px;
width: 100%;
height: 100%;
box-sizing: border-box;
overflow-y: hidden;
border-radius: 3px;
padding-bottom: 20px;
.content {
background-color: #fff;
width: 100%;
height: 100%;
border-radius: 6px;
padding: 10px;
// overflow-y: scroll;
overflow: hidden;
display: flex;
padding: 10px 0;
flex-direction: column;
// 1.標題及圖像說明
.content-desc {
margin: 0px 10px;
.title {
font-size: 16px;
border-left: 5px solid #2d8cf0;
padding-left: 10px;
margin-bottom: 16px;
}
.desc {
margin-left: 18px;
}
}
// 2.圖像區域
.content-image {
display: flex;
justify-content: rows;
margin: 20px 30px;
li {
width: 180px;
height: 180px;
margin-right: 20px;
position: relative;
.delete-img {
display: none;
}
&:hover {
.delete-img {
display: block;
position: absolute;
width: 180px;
height: 40px;
line-height: 40px;
left: 0px;
top: 140px;
background: rgba(59, 60, 61, 0.5);
// box-sizing: content-box;
z-index: 999;
cursor: pointer;
text-align: right;
i {
margin: 8px 10px 0 0;
display: block;
font-size: 24px;
color: white;
}
}
}
}
img {
width: 180px;
height: 180px;
border-radius: 4px;
}
.upload-img:hover {
border: 1px dashed #92cccc;
}
}
}
// 裁剪圖像對話框
.cropImageForm {
.img-crop {
// 1.截圖區域
.imgCrop-content {
margin: 0 20px;
display: flex;
display: -webkit-flex;
justify-content: flex-start;
-webkit-justify-content: flex-start;
.cropper-content {
width: 350px;
height: 350px;
margin-right: 40px;
}
.preview-content {
.show-preview {
// border: 1px solid #ccc;
box-sizing: border-box;
width: 150px;
height: 150px;
overflow: hidden;
flex: 1;
-webkit-flex: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
-webkit-justify-content: center;
.preview {
overflow: hidden;
/*border-radius: 50%;*/
/*border: 1px solid #cccccc;*/
background: #fff;
margin-left: 0px;
}
}
.desc {
margin-top: 10px;
text-align: center;
}
.el-button {
margin: 10px 40px;
}
}
}
// 2.操作按鈕區域
.btn-content {
width: 350px;
margin: 10px 20px;
text-align: center;
// #uploads {
// position: absolute;
// clip: rect(0 0 0 0);
// }
.btn {
height: 32px;
width: 32px;
font-size: 20px;
margin: 3px 5px;
background-color: #fff;
border: 1px solid #999;
border-radius: 4px;
}
}
}
.btn-footer {
width: 100%;
text-align: right;
padding-right: 20px;
margin-top: -20px;
}
}
}
</style>