赞
踩
效果:
一个手指拖动,可以移动图片,两个手指拖动可以缩放。
下载该项目:
git clone https://github.com/Q956164483/vue-image-cropper.git
运行:
npm i
cd vue-image-cropper
npm run serve
1.复制“vue-image-cropper”项目中的 ./src/components/imageCropper.vue文件 (imageCropper.vue需要引入exif-small.js)
2.在需要使用的页面直接引入imageCropper组件,并绑定cropperConfig配置参数和裁剪之后的回调函数callback。
3.安装lrz。
npm i lrz -S
<image-cropper ref="imageCropper" :cropperConfig="cropperConfig" :callback="loadImage"></image-cropper>
- cropperConfig: {
- width: 1, // 裁剪宽度(比例)
- height: 1, // 裁剪高度(比例)
- quality: 0.7, // 图片质量(0~1之间)
- maxWidth: 750 // 导出的图片的最大宽度
- }
- loadImage (data) {
- console.log(data);//data为图片base64字符串,可以直接放入img的src
- }
可以选择支持一下博主,花个几十积分,我的代码:
uni-app的图片裁剪nice-cropper.rar_uniapp图片裁剪,uniapp图片裁剪-互联网文档类资源-CSDN下载
如果饭都吃不起,就选择如下:
安装lrz:
npm i lrz -S
1.效果。
2.imageCropper.vue的代码:
- <template>
- <div ref="cropperPage" class="cropper-page" v-show="isShow">
- <div @click="cancel()" class="icon icon-back"></div>
- <input ref="file" type="file" accept="image/*" @change="readImage">
- <img alt="" class="cropper-img" :style="imageStyle" ref="img">
- <div class="cover box box-ac box-jc" :style="{height: coverHeight + 'px'}">
- <!-- 请调整图片 -->
- </div>
- <div ref="cropBox" class="cropper-box" @touchstart.prevent="touchStart" @touchmove.prevent="touchMove"></div>
- <div class="cover cover box box-ac box-jc" :style="{height: coverHeight + 'px'}">
- <div class="box box-f1 box-jc box-fh">
- <div class="btn" @click="cancel">取消</div>
- <!--重选checkPhoto-->
- </div>
- <div class="box box-f1 box-jc box-fh">
- <div class="btn sure" @click="confirm">确定</div>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- import lrz from 'lrz'
- const getDinstance = function(point0, point1) {
- return Math.sqrt(Math.pow(point0.pageY - point1.pageY, 2) + Math.pow(point0.pageX - point1.pageX, 2))
- }
- export default {
- name: 'imageCropper',
- props: {
- //裁剪确认后的回调,结果是图片数据。
- callback: {
- type: Function,
- default () {}
- },
- cropperConfig: {
- type: Object,
- default () {
- return {
- width: 1,//裁剪宽度(比例)
- height: 1,//裁剪高度(比例)
- quality: 0.7,//图片质量(0~1之间)
- maxWidth: 640//导出的图片最大宽度
- }
- }
- }
- },
- data() {
- return {
- coverHeight: 0,
- cropperHeight: 0,
- imgInitTop: 0,
- amplitude: 0,
- imageState: {
- left: 0,
- top: 0,
- scale: 1,
- width: 0,
- height: 0,
- originX: 0,
- originY: 0
- },
- distance: 0,
- imageStyle: {
- top: '0',
- transform: 'translate3d(0px, 0px, 0px) scale(1)',
- transformOrigin: 'left top'
- },
- cropBoxRect: {},
- touchPos: {
- x: 0,
- y: 0
- },
- isShow: false,
- minScale: 0,
- info: '',
- orientation: ''
- }
- },
- watch: {
- 'imageState': {
- handler(val) {
- this.imageStyle.transform = 'translate3d(-' + val.left + 'px, -' + val.top + 'px, 0px) scale(' + val.scale + ')'
- },
- deep: true
- }
- },
- methods: {
- cancel() {
- this.file = null
- this.isShow = false
- },
- checkPhoto() {
- this.$refs.file.click()
- },
- readImage($event) {
- var self = this
- var file = $event.target.files[0]
- lrz(file)
- .then(rst => {
- self.orientation = 1
- self.$refs.img.onload = () => {
- self.initCropper()
- }
- self.$refs.img.src = rst.base64
- $event.target.value = null
- })
- },
- initCropper() {
- this.isShow = true // 显示裁剪界面
- this.$nextTick(() => {
- let cropperPage = this.$refs.cropperPage
- let pageWidth = cropperPage.clientWidth
- let pageHeight = cropperPage.clientHeight
- let cropBox = this.$refs.cropBox
- let cropBoxWidth = cropBox.clientWidth
- let cropBoxHeight = Math.floor(cropBoxWidth * (+this.cropperConfig.height) / (+this.cropperConfig.width))
- this.$refs.cropBox.style.height = cropBoxHeight + 'px'
- this.coverHeight = (pageHeight - cropBoxHeight) / 2
- let cropBoxTop = this.coverHeight
- this.imageState.left = 0
- this.imageState.top = 0
- this.imageStyle.top = cropBoxTop + 'px'
- this.cropBoxRect = {
- left: 0,
- top: cropBoxTop,
- width: pageWidth,
- height: cropBoxHeight
- }
- let img = this.$refs.img
- var width = this.imageState.width = img.naturalWidth
- var height = this.imageState.height = img.naturalHeight
- // 计算imageState
- if (width > height) {
- this.minScale = this.imageState.scale = this.cropBoxRect.height / height
- this.imageState.left = (width * this.imageState.scale - this.cropBoxRect.width) / 2
- } else {
- this.minScale = this.imageState.scale = this.cropBoxRect.width / width
- this.imageState.top = (height * this.imageState.scale - this.cropBoxRect.height) / 2
- }
- })
- },
- confirm() {
- let self = this
- let imageState = this.imageState
- let cropBoxRect = this.cropBoxRect
- // 导出图片的最大宽度
- let maxWidth = this.cropperConfig.maxWidth
- let scale2 = maxWidth / cropBoxRect.width
- let scale = imageState.scale * scale2
- let width = cropBoxRect.width * scale2
- let height = cropBoxRect.height * scale2
- let left = imageState.left * scale2
- let top = imageState.top * scale2
- let image = this.$refs.img
- let canvas = document.createElement('canvas')
- let ctx = canvas.getContext('2d')
- // ios 的照片有拍摄的角度信息 参考 http://www.bcty365.com/content-142-3055-1.html
- let orientation = this.orientation
- switch (orientation) {
- case 1:
- canvas.width = width
- canvas.height = height
- ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, 0, 0, width, height)
- break
- case 6:
- canvas.width = height
- canvas.height = width
- ctx.rotate(90 * Math.PI / 180)
- ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, 0, -height, width, height)
- break
- case 8:
- canvas.width = height
- canvas.height = width
- ctx.rotate(-90 * Math.PI / 180)
- ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, -width, 0, width, height)
- break
- case 3:
- canvas.width = width
- canvas.height = height
- ctx.rotate(180 * Math.PI / 180)
- ctx.drawImage(image, left / scale, top / scale, width / scale, height / scale, -width, -height, width, height)
- break
- }
- let dataUrl = canvas.toDataURL('image/jpeg', this.cropperConfig.quality)
- self.callback(dataUrl)
- self.isShow = false
- },
- getFocalPoint(point0, point1) {
- return {
- x: (point0.pageX + point1.pageX) / 2,
- y: (point0.pageY + point1.pageY) / 2
- }
- },
- touchStart(event) {
- var fingerCount = event.touches.length
- if (fingerCount) {
- // 记录触摸初始位置
- let touchEvent = event.touches[0]
- this.touchPos = {
- x: touchEvent.clientX,
- y: touchEvent.clientY
- }
- }
- if (fingerCount >= 2) {
- // 获取两点距离、中点位置;两点距离old/new=放大倍数;中点位置,缩放中心;
- let point0 = event.touches[0]
- let point1 = event.touches[1]
- this.distance = getDinstance(point0, point1)
- this.touchPos = this.getFocalPoint(point0, point1)
- // 设置缩放倍数,
- }
- },
- touchMove(event) {
- // 根据触摸点位移,移动图片,重置触摸点位置
- var fingerCount = event.touches.length
- var touchEvent = event.touches[0]
- if (fingerCount === 1) {
- let distX = touchEvent.pageX - this.touchPos.x
- let distY = touchEvent.pageY - this.touchPos.y
- let newX = this.imageState.left - distX
- let newY = this.imageState.top - distY
- let scale = this.imageState.scale
- // alert(scale)
- let maxX = this.imageState.width * scale - this.cropBoxRect.width
- let maxY = this.imageState.height * scale - this.cropBoxRect.height
- this.imageState.left = newX < 0 ? 0 : (newX > maxX ? maxX : newX)
- this.imageState.top = newY < 0 ? 0 : (newY > maxY ? maxY : newY)
- this.touchPos.x = touchEvent.pageX
- this.touchPos.y = touchEvent.pageY
- } else if (fingerCount > 1) {
- let point0 = event.touches[0]
- let point1 = event.touches[1]
- let distance = getDinstance(point0, point1)
- let zoom = distance / this.distance
- let scale = zoom * this.imageState.scale
- let maxX = this.imageState.width * scale - this.cropBoxRect.width
- let maxY = this.imageState.height * scale - this.cropBoxRect.height
- let touchPos = this.getFocalPoint(point0, point1)
- let newX = zoom * (this.imageState.left + touchPos.x) - touchPos.x
- let newY = zoom * ((this.imageState.top - this.imgInitTop) + touchPos.y) - touchPos.y + this.imgInitTop
- // 限制缩放
- // 图片新位置:由中点位置确认;(新位置到中点)/(旧位置到中点)=(new scale)/(old scale)
- // newLeft - touchPos.x = (distance / this.distance) * (oldLetf - touchPos.x)
- // oldLeft = 0 - this.imageState.left
- // oldTop = imgInitTop - this.imageState.top
- this.distance = distance
- if (scale < this.minScale) {
- this.imageState.scale = this.minScale
- } else {
- this.imageState.scale = scale
- this.imageState.left = newX < 0 ? 0 : (newX > maxX ? maxX : newX)
- this.imageState.top = newY < 0 ? 0 : (newY > maxY ? maxY : newY)
- }
- this.touchPos = touchPos
- }
- }
- }
- }
- </script>
-
- <style lang="scss" scoped>
- $themeColor:#409EFF;
- .box {
- display: flex;
- position: relative;
- }
- .box-f1 {
- flex: 1;
- }
- .box-ac {
- align-items: center
- }
- .box-jc {
- justify-content: center
- }
- .box-ver {
- flex-direction: column
- }
- .cropper-page {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 10;
- background-color: #fff;
- overflow: hidden;
- }
- .cover {
- color: #FFF;
- font-size: .4rem;
- background-color: rgba(0, 0, 0, 0.2);
- }
- .cropper-box {
- // border: 1px dashed #FFF;
- border: 2px dashed #FFF;
- }
- .cropper-img {
- position: absolute;
- z-index: -1;
- }
- input[type="file"] {
- opacity: 0;
- position: fixed;
- top: -1000px;
- left: -1000px;
- }
- .btn {
- font-size: .6rem;
- padding: .1rem .3rem;
- border: .02rem solid;
- color: #FFF;
- border-radius: .4rem;
- width:80px;
- height:35px;
- display: flex;
- align-items: center;
- justify-content: center;
- background:#909399;
- &.sure {
- background: $themeColor;
- }
- }
- </style>
3.简单使用。
- <template>
- <div>
- <image-cropper ref="imageCropper" :cropperConfig="cropperConfig" :callback="loadImage"></image-cropper>
- <button @click="selectFile()">打开</button>
- <div>
- <img v-if="img" :src="img" style="width:200px;height:200px;"/>
- </div>
- </div>
- </template>
-
- <script>
- import imageCropper from '@/components/imageCropper'
- export default {
- name: 'Home',
- components: {imageCropper},
- data() {
- return {
- img:'',
- cropperConfig: {
- width: 1,
- height: 1,
- quality: 0.7,
- maxWidth: 750
- }
- };
- },
- mounted() {
-
- },
- methods: {
- selectFile () {
- this.$refs.imageCropper.checkPhoto()
- },
- // 图片裁剪之后的回调
- loadImage (data) {
- // this.images.push(data)
- console.log(data)
- this.img=data;
- },
- },
- };
- </script>
-
- <style lang="scss" scoped>
-
- </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。