前幾天遇到一個(gè)上傳頭像的需求 但是上傳的圖片可能會(huì)存在位置問(wèn)題,導(dǎo)致上傳的圖片不能正常的顯示出來(lái)于是就想著使用vue來(lái)寫一個(gè)圖片裁剪上傳的demo 我使用的是vue-cropper
vue-cropper
前幾天遇到一個(gè)上傳頭像的需求 但是上傳的圖片可能會(huì)存在位置問(wèn)題捏鱼,導(dǎo)致上傳的圖片不能正常的顯示出來(lái)于是就想著使用vue來(lái)寫一個(gè)圖片裁剪上傳的demo 我使用的是vue-cropper
vue-cropper
vue-cropper是一個(gè)能夠通過(guò)canva裁剪圖片的js工具庫(kù)。
安裝:
npm i vue-cropper
使用方法:
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
我們?cè)賛ain.js引用后就可以使用了
<template>
<div >
<label class="btn btn-orange" for="uploads" style="display:inline-block;width: 70px;padding: 0;text-align: center;line-height: 28px;">選擇圖片</label>
<input type="file" id="uploads" :value="imgFile" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="+" title="放大" @click="changeScale(1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="-" title="縮小" @click="changeScale(-1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="?" title="左旋轉(zhuǎn)" @click="rotateLeft">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="?" title="右旋轉(zhuǎn)" @click="rotateRight">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="↓" title="下載" @click="down('blob')">
<input type="button" class="btn btn-blue" value="上傳頭像" @click="finish('blob')">
<div class="info-item" style="flex:1;margin-left:-160px;margin-top:30px;">
<div class="line" style="margin-top: 85px;">
<div class="cropper-content" style="margin-top:-60px;width: 580px;">
<div class="cropper">
<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"
@realTime="realTime"
@imgLoad="imgLoad"
></vueCropper>
</div>
<div>
<div class="show-preview" :style="{'width': '150px', 'height':'155px', 'overflow': 'hidden', 'margin': '5px'}">
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
name: 'HelloWorld',
data() {
return {
headImg:'',
//剪切圖片上傳
crap: false,
previews: {},
option: {
img: '',
outputSize:1, //剪切后的圖片質(zhì)量(0.1-1)
full: false,//輸出原圖比例截圖 props名full
outputType: 'png',
canMove: true,
original: false,
canMoveBox: true,
autoCrop: true,
autoCropWidth: 150,
autoCropHeight: 150,
fixedBox: true
},
fileName:'', //本機(jī)文件地址
downImg: '#',
imgFile:'',
uploadImgRelaPath:'', //上傳后的圖片的地址(不帶服務(wù)器域名)
}
},
components: {
VueCropper
},
methods: {
//放大/縮小
changeScale(num) {
console.log('changeScale')
num = num || 1;
this.$refs.cropper.changeScale(num);
},
//坐旋轉(zhuǎn)
rotateLeft() {
console.log('rotateLeft')
this.$refs.cropper.rotateLeft();
},
//右旋轉(zhuǎn)
rotateRight() {
console.log('rotateRight')
this.$refs.cropper.rotateRight();
},
//上傳圖片(點(diǎn)擊上傳按鈕)
finish(type) {
console.log('finish')
let _this = this;
let formData = new FormData();
// 輸出
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
let img = window.URL.createObjectURL(data)
this.model = true;
this.modelSrc = img;
formData.append("file", data, this.fileName);
// 這里上傳post
})
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true;
this.modelSrc = data;
})
}
},
// 實(shí)時(shí)預(yù)覽函數(shù)
realTime(data) {
console.log('realTime')
this.previews = data
},
//下載圖片
down(type) {
console.log('down')
var aLink = document.createElement('a')
aLink.download = 'author-img'
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
this.downImg = window.URL.createObjectURL(data)
aLink.href = window.URL.createObjectURL(data)
aLink.click()
})
} else {
this.$refs.cropper.getCropData((data) => {
this.downImg = data;
aLink.href = data;
aLink.click()
})
}
},
//選擇本地圖片
uploadImg(e, num) {
console.log('uploadImg');
var _this = this;
//上傳圖片
var file = e.target.files[0]
_this.fileName = file.name;
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
alert('圖片類型必須是.gif,jpeg,jpg,png,bmp中的一種')
return false
}
var reader = new FileReader();
reader.onload =(e) => {
let data;
if (typeof e.target.result === 'object') {
// 把Array Buffer轉(zhuǎn)化為blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
}
else {
data = e.target.result
}
if (num === 1) {
_this.option.img = data
} else if (num === 2) {
_this.example2.img = data
}
}
// 轉(zhuǎn)化為base64
// reader.readAsDataURL(file)
// 轉(zhuǎn)化為blob
reader.readAsArrayBuffer(file);
},
imgLoad (msg) {
console.log('imgLoad')
console.log(msg)
}
}
}
</script>
<style scoped lang="stylus">
.show-preview
flex 1
-webkit-flex 1
display flex
display -webkit-flex
justify-content center
-webkit-justify-content center
background blue
.preview
overflow hidden
border-radius 50%;
border 1px solid #cccccc
background #cccccc
.info
width 720px
margin 0 auto
.oper-dv
height:20px
text-align:right
margin-right:100px
a
font-weight 500
&:last-child
margin-left 30px
.info-item
margin-top 15px
label
display inline-block
width 100px
text-align right
.sel-img-dv
position relative
.sel-file
position absolute
width 90px
height 30px
opacity 0
cursor pointer
z-index 2
.sel-btn
position absolute
cursor pointer
z-index 1
.cropper-content
display flex
display -webkit-flex
justify-content flex-end
-webkit-justify-content flex-end
.cropper
width 260px
height 260px
</style>
以上是具體的代碼實(shí)現(xiàn)
vue-cropper是一個(gè)能夠通過(guò)canva裁剪圖片的js工具庫(kù)卿樱。
安裝:
npm i vue-cropper
使用方法:
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
我們?cè)賛ain.js引用后就可以使用了
<template>
<div >
<label class="btn btn-orange" for="uploads" style="display:inline-block;width: 70px;padding: 0;text-align: center;line-height: 28px;">選擇圖片</label>
<input type="file" id="uploads" :value="imgFile" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="+" title="放大" @click="changeScale(1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="-" title="縮小" @click="changeScale(-1)">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="?" title="左旋轉(zhuǎn)" @click="rotateLeft">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="?" title="右旋轉(zhuǎn)" @click="rotateRight">
<input type="button" class="oper" style="height:30px;width:33px;font-size:20px;margin:3px 5px;" value="↓" title="下載" @click="down('blob')">
<input type="button" class="btn btn-blue" value="上傳頭像" @click="finish('blob')">
<div class="info-item" style="flex:1;margin-left:-160px;margin-top:30px;">
<div class="line" style="margin-top: 85px;">
<div class="cropper-content" style="margin-top:-60px;width: 580px;">
<div class="cropper">
<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"
@realTime="realTime"
@imgLoad="imgLoad"
></vueCropper>
</div>
<div>
<div class="show-preview" :style="{'width': '150px', 'height':'155px', 'overflow': 'hidden', 'margin': '5px'}">
<div :style="previews.div" class="preview">
<img :src="previews.url" :style="previews.img">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
name: 'HelloWorld',
data() {
return {
headImg:'',
//剪切圖片上傳
crap: false,
previews: {},
option: {
img: '',
outputSize:1, //剪切后的圖片質(zhì)量(0.1-1)
full: false,//輸出原圖比例截圖 props名full
outputType: 'png',
canMove: true,
original: false,
canMoveBox: true,
autoCrop: true,
autoCropWidth: 150,
autoCropHeight: 150,
fixedBox: true
},
fileName:'', //本機(jī)文件地址
downImg: '#',
imgFile:'',
uploadImgRelaPath:'', //上傳后的圖片的地址(不帶服務(wù)器域名)
}
},
components: {
VueCropper
},
methods: {
//放大/縮小
changeScale(num) {
console.log('changeScale')
num = num || 1;
this.$refs.cropper.changeScale(num);
},
//坐旋轉(zhuǎn)
rotateLeft() {
console.log('rotateLeft')
this.$refs.cropper.rotateLeft();
},
//右旋轉(zhuǎn)
rotateRight() {
console.log('rotateRight')
this.$refs.cropper.rotateRight();
},
//上傳圖片(點(diǎn)擊上傳按鈕)
finish(type) {
console.log('finish')
let _this = this;
let formData = new FormData();
// 輸出
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
let img = window.URL.createObjectURL(data)
this.model = true;
this.modelSrc = img;
formData.append("file", data, this.fileName);
// 這里上傳post
})
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true;
this.modelSrc = data;
})
}
},
// 實(shí)時(shí)預(yù)覽函數(shù)
realTime(data) {
console.log('realTime')
this.previews = data
},
//下載圖片
down(type) {
console.log('down')
var aLink = document.createElement('a')
aLink.download = 'author-img'
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
this.downImg = window.URL.createObjectURL(data)
aLink.href = window.URL.createObjectURL(data)
aLink.click()
})
} else {
this.$refs.cropper.getCropData((data) => {
this.downImg = data;
aLink.href = data;
aLink.click()
})
}
},
//選擇本地圖片
uploadImg(e, num) {
console.log('uploadImg');
var _this = this;
//上傳圖片
var file = e.target.files[0]
_this.fileName = file.name;
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
alert('圖片類型必須是.gif,jpeg,jpg,png,bmp中的一種')
return false
}
var reader = new FileReader();
reader.onload =(e) => {
let data;
if (typeof e.target.result === 'object') {
// 把Array Buffer轉(zhuǎn)化為blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
}
else {
data = e.target.result
}
if (num === 1) {
_this.option.img = data
} else if (num === 2) {
_this.example2.img = data
}
}
// 轉(zhuǎn)化為base64
// reader.readAsDataURL(file)
// 轉(zhuǎn)化為blob
reader.readAsArrayBuffer(file);
},
imgLoad (msg) {
console.log('imgLoad')
console.log(msg)
}
}
}
</script>
<style scoped lang="stylus">
.show-preview
flex 1
-webkit-flex 1
display flex
display -webkit-flex
justify-content center
-webkit-justify-content center
background blue
.preview
overflow hidden
border-radius 50%;
border 1px solid #cccccc
background #cccccc
.info
width 720px
margin 0 auto
.oper-dv
height:20px
text-align:right
margin-right:100px
a
font-weight 500
&:last-child
margin-left 30px
.info-item
margin-top 15px
label
display inline-block
width 100px
text-align right
.sel-img-dv
position relative
.sel-file
position absolute
width 90px
height 30px
opacity 0
cursor pointer
z-index 2
.sel-btn
position absolute
cursor pointer
z-index 1
.cropper-content
display flex
display -webkit-flex
justify-content flex-end
-webkit-justify-content flex-end
.cropper
width 260px
height 260px
</style>
以上是具體的代碼實(shí)現(xiàn)