24 12 2021

创建invinbg-image-cropper组件,代码如下

<template>
	<view :class="systemInfo.windowWidth >= 1204 ? 'shade' : ''" v-show="show">
		<view class="vue-cropper" ref="cropper" :style="{ top : `${containerTop}px`, width:systemInfo.windowWidth >= 1204 ? `${windowWidth}px` : '',height:systemInfo.windowWidth >= 1204 ? `${containerHeight}px` : '' ,margin:systemInfo.windowWidth >= 1204 ? '0 auto': ''}" v-show="show">
			<view class="cropper-box"> 
			<!-- @mouseup.stop.prevent="imgMoveEnd1" @mousemove.stop.prevent="imgMoveing1" -->
				<view class="cropper-box-canvas" @mousedown.stop.prevent="imgTouchStart1" @mouseup.stop.prevent="imgMoveEnd" @mousemove.stop.prevent="imgMoveing1"  @touchstart.stop.prevent="imgTouchStart" @touchmove.stop.prevent="imgMoveing" @touchend.stop.prevent="imgMoveEnd" :style="{
						'width': imageWidth + 'px',
						'height': imageHeight + 'px',
						'transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ x / scale + 'px,' + y / scale + 'px,' + '0)'
						+ 'rotateZ('+ rotate * 90 +'deg)'
						}">
					<image :src.sync="src" alt="cropper-img" ref="cropperImg" mode="scaleToFill" class="uni-image"></image>
				</view>
			</view>
			<view class="cropper-drag-box cropper-modal cropper-move pointer-events"></view>
			<view class="cropper-crop-box" :class="{'pointer-events': cropFixed}" :style="{'width': cropW + 'px','height': cropH + 'px','transform': 'translate3d('+ cropOffsertX + 'px,' + cropOffsertY + 'px,' + '0)'}">
				<view class="cropper-view-box">
					<image :style="{'width': imageWidth + 'px','height': imageHeight + 'px','transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ (x - cropOffsertX) / scale  + 'px,' + (y - cropOffsertY) / scale + 'px,' + '0)' + 'rotateZ('+ rotate * 90 +'deg)'}" mode="scaleToFill" :src="src" alt="cropper-img"></image>
				</view>

				<!-- <view v-if="!cropFixed" class="cropper-face cropper-move" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="cropMoveing"></view> -->
				<view v-if="!cropFixed" class="cropper-face cropper-move" @mousedown.stop.prevent="touchStart1($event, 'crop_move')" @mouseup.stop.prevent="knob_down =false,drag_move=false,crop_move=false" @mousemove.stop.prevent="cropMoveing1" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="cropMoveing"></view>
			  
				<view class="crop-line line-w"></view>
				<view class="crop-line line-a"></view>
				<view class="crop-line line-s"></view>
				<view class="crop-line line-d"></view>
				<block v-if="!cropFixed">
					<view class="crop-point point-lt" @mousedown.stop.prevent="touchStart1($event, 'drag_move')" @mouseup.stop.prevent="knob_down =false,drag_move=false,crop_move=false" @mousemove.stop.prevent="dragMove1($event, 'left-top')"  @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'left-top')"></view>
					<!-- <view class="crop-point point-mt" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'middle-top')"></view> -->
					<view class="crop-point point-rt" @mousedown.stop.prevent="touchStart1($event, 'drag_move')" @mouseup.stop.prevent="knob_down =false,drag_move=false,crop_move=false" @mousemove.stop.prevent="dragMove1($event, 'right-top')"  @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'right-top')"></view>
					<!-- <view class="crop-point point-ml" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'middle-left')"></view> -->
					<!-- <view class="crop-point point-mr" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'middle-right')"></view> -->
					<view class="crop-point point-lb" @mousedown.stop.prevent="touchStart1($event, 'drag_move')" @mouseup.stop.prevent="knob_down =false,drag_move=false,crop_move=false" @mousemove.stop.prevent="dragMove1($event, 'left-bottom')"  @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'left-bottom')"></view>
					<!-- <view class="crop-point point-mb" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'middle-bottom')"></view> -->
					<view class="crop-point point-rb" @mousedown.stop.prevent="touchStart1($event, 'drag_move')" @mouseup.stop.prevent="knob_down =false,drag_move=false,crop_move=false" @mousemove.stop.prevent="dragMove1($event, 'right-bottom')"  @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="dragMove($event, 'right-bottom')"></view>
				</block>
			</view>

			<canvas canvas-id="myCanvas" class="cropper-canvas" :style="{ 'width': canvasW + 'px','height': canvasH + 'px' }"></canvas>

			<view class="btn-group">
				<view class="btn-item reset-btn" v-show="showResetBtn" @tap="init"></view>
				<view class="btn-item rotate-btn" v-show="showRotateBtn" @tap="rotateHandler"></view>
			</view>

			<view class="uni-info__ft">
				<view class="uni-modal__btn uni-modal__btn_default" style="color: rgb(0, 0, 0);" @tap="cancel">取消</view>
				<view class="uni-modal__btn uni-modal__btn_primary" style="color: rgb(0, 122, 255);" @tap="confirm">确定</view>
			</view>
		</view>
	</view>
</template>

<script>
	import {
		pathToBase64,
		base64ToPath
	} from 'image-tools';
    export default {
        name: 'image-cropper',
        props: {
			whScale: {
			    type: [Number,String],
			    default: 1,
			},
			maxWidth: {
			    type: [Number,String],
			    default: 1440,
			},
			width:{
				type: [Number,String],
				default: 0,
			},
			height:{
				type: [Number,String],
				default: 0,
			},
			isBase64:{
				type: Boolean,
				default: true,
			},
   //          cropWidth: {
   //              type: [Number,String],
   //              default: 200,
   //          },
			// cropHeight: {
			//     type: [Number,String],
			//     default: 200
			// },
            cropFixed: {
                type: Boolean,
                default: false,
            },
            src: {
                type: String,
            },
            showResetBtn: {
                type: Boolean,
                default: true,
            },
            showRotateBtn: {
                type: Boolean,
                default: true,
            }
        },
        data() {
            const sysInfo = uni.getSystemInfoSync();
            const pixelRatio = sysInfo.pixelRatio
            return {
                show: false,
                scale: 1,
                rotate: 0,
                cropW: 0,
                cropH: 0,
                cropOldW: 0,
                cropOldH: 0,
                sysInfo: sysInfo,
                pixelRatio: pixelRatio,
                imageRealWidth: 0,
                imageRealHeight: 0,
                cropOffsertX: 0,
                cropOffsertY: 0,
                startX: 0,
                startY: 0,
                // 裁剪框与边界间距
                border: 5,
                x: 0,
                y: 0,
                startL: 0,
                oldScale: 1,
				knob_down:false,
				drag_move:false,
				crop_move:false,
				img_move:false,
				real_ratio:1, //图片缩放比
				canvasW:0,
				canvasH:0
            }
        },
        watch: {
			cropW(){
				let ratio = this.imageRealWidth / this.imageWidth
				this.canvasW = this.cropW * ratio
			},
			cropH(){
				let ratio = this.imageRealHeight / this.imageHeight
				this.canvasH = this.cropH * ratio
			},
            src(val) {
				console.log('watch-src');
                if(val.length > 0) {
                    this.init()
                }
            },
            show(val) {
				console.log('watch-show');
                if(!val) {
                    this.$emit('update:src', null); 
                }
            }
        },
        computed: {
			
            containerTop() {
				console.log('computed-containerTop1');
                let top = 0
                // #ifdef H5
				if (navigator.userAgent.indexOf('Mobile')>-1) {  
				    console.log('移动端')  
					top = 0;
				}else{
					console.log('pc端');
					top = 'auto';
				}
                // #endif
                return top;
            },
            // 容器高度
            containerHeight() {
				console.log('computed-containerHeight');
                return this.windowHeight - 48;
            },
            // 屏幕宽度
            windowWidth() {
				console.log('computed-windowWidth');
				if(this.systemInfo.windowWidth >= 1204){
					return this.sysInfo.windowWidth/4;
				}else{
					return this.sysInfo.windowWidth
				}
                
            },
            windowHeight() {
				console.log('computed-windowHeight');
                return this.sysInfo.windowHeight;
            },
            // 图片宽高比
            imageRatio() {
				console.log('computed-imageRatio');
                if (this.imageRealHeight > 0) {
                    return this.imageRealWidth / this.imageRealHeight
                }
                return 0
            }, 
            // 等比缩放后的宽度
            imageWidth() {
				console.log('computed-imageWidth');
                if (this.imageRatio >= 1) {
                    return this.windowWidth*0.95
                }
				
                return this.windowWidth * this.imageRatio
            },
            // 等比缩放后的高度
            imageHeight() {
				console.log('computed-imageHeight');
                if (this.imageRatio >= 1) {
                    return this.windowWidth / this.imageRatio
                }
                return this.windowWidth
            },
        },
        methods: {
            rotateHandler() {
				this.knob_down = false;
				console.log('rotateHandler');
                if(this.rotate == 3) {
                    this.rotate = 0;
                } else {
                    ++this.rotate
                }
            },
            init() {
				console.log('init',this.isBase64);
				this.knob_down = false;
                this.rotate = 0;
                this.scale = 1;
				// this.cropWidth = Number(this.cropWidth)
				this.whScale = Number(this.whScale)
				// this.cropHeight = Number(this.cropHeight)
    //             this.cropH = this.imageHeight
				// if(this.whScale){
				// 	this.cropW = this.cropH * this.whScale
				// }else{
				// 	this.cropW = this.imageWidth
				// }
				if(this.width > 0 && this.height > 0){
					this.whScale = this.width / this.height;
				}
                uni.showLoading({
                    title: '图片加载中...',
                })
                this.loadImage(this.src).then((e) => {
                    uni.hideLoading()
                }).catch((e) => {
                    uni.hideLoading()
                    uni.showModal({
                        title: '标题',
                        content: '图片加载失败'
                    })
                })
            },
            loadImage(src) {
				
				console.log('loadImage-start');
				
                const _this = this
                return new Promise((resolve, reject) => {
					console.log('loadImage-Promise');
                    uni.getImageInfo({
                        src: src,
                        success: (res) => {
							console.log('loadImage-getImageInfo-success');
                            _this.imageRealWidth = res.width
                            _this.imageRealHeight = res.height
							//底下注释掉,使用传入值进行计算 2021-12-9
							_this.cropH = _this.imageHeight;
							if(_this.width >0 && _this.height>0){
								_this.cropW = _this.width * _this.whScale;
								_this.cropH = _this.height * _this.whScale;
								if(_this.cropW > _this.imageWidth){
									var rao = _this.imageWidth / _this.cropW;
									_this.cropW = _this.imageWidth -10;
									_this.cropH = _this.cropH  * rao -10;
								}
								console.log(_this.cropW,_this.cropH);
							}else if(_this.whScale){
								_this.cropW = _this.cropH * _this.whScale
								if(_this.cropW > _this.imageWidth){
									_this.cropW = _this.imageWidth
									_this.cropH = _this.cropW / _this.whScale
								}
							}else{
								_this.cropW = _this.imageWidth
								// _this.cropW = _this.cropW * 0.9
								_this.cropW = _this.cropW
								_this.cropH = _this.cropH * 0.9
							}
							
                            _this.cropOffsertX = _this.windowWidth / 2 - _this.cropW / 2
                            _this.cropOffsertY = (_this.windowHeight / 2 - _this.cropH / 2)- 24
                            _this.show = true

                            _this.$nextTick(() => {
                                _this.x = _this.windowWidth / 2 - _this.imageWidth / 2
                                _this.y = _this.containerHeight / 2 - _this.imageHeight / 2
                            });
                            resolve(res)
                        },
                        fail: (e) => {
							console.log('loadImage-getImageInfo-fail');
							console.log(e);
							console.log(src);
                            _this.show = false
                            reject(e)
                        }
                    })
                });
				console.log('loadImage-end');
            },
            cancel() {
				console.log('cancel');
                this.show = false
                this.$emit('cancel')
            },
            confirm(event) {
				console.log('event');
                uni.showLoading({
                    title: '裁剪中...',
                })
                const _this = this
                const ctx = uni.createCanvasContext('myCanvas', _this);

				const wbili = _this.imageRealWidth / _this.imageWidth;
				const hbili = _this.imageRealHeight / _this.imageHeight;
                const pixelRatio = _this.pixelRatio
                const imgage = _this.src
                const imgW = _this.imageWidth * _this.scale;
                const imgH = _this.imageHeight * _this.scale
                const rotate = _this.rotate
                let dx = _this.cropOffsertX - _this.x - (_this.imageWidth - imgW) / 2;
                let dy = _this.cropOffsertY - _this.y - (_this.imageHeight - imgH) / 2;

                ctx.setFillStyle('white')
                ctx.fillRect(0, 0, imgW, imgH)
                ctx.save()

                ctx.rotate((rotate * 90 * Math.PI) / 180);
				console.log(rotate,imgW, imgH,_this.scale,1111)
                switch (rotate) {
                    case 1:
                        dx += (imgH-imgW) / 2
                        dy -= (imgH-imgW) / 2
                        ctx.drawImage(imgage, -(dy * hbili), dx * wbili, imgW * wbili, -(imgH * hbili));
                        break;
                    case 2:
                        ctx.drawImage(imgage, dx * wbili, dy * hbili, -(imgW * wbili), -(imgH * hbili));
                        break;
                    case 3:
                        dx += (imgH-imgW) / 2
                        dy -= (imgH-imgW) / 2
                        ctx.drawImage(imgage, dy * hbili, -(dx * wbili), -(imgW * wbili), imgH * hbili);
                        break;
                    default:
                        ctx.drawImage(imgage, -(dx * wbili), -(dy * hbili), imgW * wbili, imgH * hbili);
                        break;
                }
				
				let yuWidth = 0;
				let yuHeight = 0;
				 _this.maxWidth = + _this.maxWidth
				let yuNum = _this.cropW * wbili;
				if(_this.whScale){
					if(yuNum > _this.maxWidth){
						yuWidth = _this.maxWidth;
						yuHeight = _this.maxWidth/_this.whScale;
					}else{
						yuWidth = _this.cropW * wbili;
						yuHeight = _this.cropH * hbili;
					}
				}else{
					if(yuNum > _this.maxWidth){
						yuWidth = _this.maxWidth;
						yuHeight = _this.cropH * pixelRatio * ( _this.maxWidth/(_this.cropW * pixelRatio));
					}else{
						yuWidth = _this.cropW * pixelRatio;
						yuHeight = _this.cropH * pixelRatio;
					}
					
				}
				
                ctx.restore()
                ctx.draw(false, () => {
                    uni.canvasToTempFilePath({
                        canvasId: 'myCanvas',
						fileType:'jpg',
                        destWidth: yuWidth,
                        destHeight: yuHeight,
                        success: (res) => {
                            uni.hideLoading()
							if(_this.isBase64){
								
								//这是返回base64格式的
								_this.successWay(res.tempFilePath);
							}else{
								console.log(1111111,res.tempFilePath);
								//这是直接返回路径
								this.show = false;
								_this.$emit('confirm',res.tempFilePath);
							}
							
                        },
                        fail: (e) => {
                            uni.hideLoading()
                            uni.showModal({
                                title: '提示',
                                content: '裁剪失败'
                            })
                        }
                    }, _this);
                })

            },
			successWay:async function(_path) {
				console.log('successWay');
				let getR = await this.toBase64(_path);
				this.show = false;
				this.$emit('confirm', getR)
			},
			imgTouchStart1(e) {
				console.log(e,9999)
				this.img_move = true;
				console.log('imgTouchStart');
			    if(e.touches.length == 2) {
			        this.oldScale = this.scale
			        this.scaling = true
			        const x = e.touches[0].pageX - e.touches[1].pageX
			        const y = e.touches[0].pageY - e.touches[1].pageY
			        const hypotenuse = Math.sqrt(
			            Math.pow(x, 2) +
			            Math.pow(y, 2)
			        )
			
			        this.startL = Math.max(x, y, hypotenuse)
			        uni.showModal({
			            content: this.startL
			        })
			    } else {
			        this.startX = e.pageX - this.x
			        this.startY = e.pageY - this.y
			    }
			},
            imgTouchStart(e) {
				console.log('imgTouchStart');
                if(e.touches.length == 2) {
                    this.oldScale = this.scale
                    this.scaling = true
                    const x = e.touches[0].pageX - e.touches[1].pageX
                    const y = e.touches[0].pageY - e.touches[1].pageY
                    const hypotenuse = Math.sqrt(
                        Math.pow(x, 2) +
                        Math.pow(y, 2)
                    )

                    this.startL = Math.max(x, y, hypotenuse)
                    uni.showModal({
                        content: this.startL
                    })
                } else {
                    this.startX = e.touches[0].pageX - this.x
                    this.startY = e.touches[0].pageY - this.y
                }
            },
			imgMoveing1(e) {
				console.log('imgMoveing1');
				if(this.img_move){
					if(this.scaling && e.touches.length == 2) {
						let scale = this.oldScale
				
						const x = e.touches[0].pageX - e.touches[1].pageX
						const y = e.touches[0].pageY - e.touches[1].pageY
						const hypotenuse = Math.sqrt(
							Math.pow(x, 2) +
							Math.pow(y, 2)
						)
				
						const newL = Math.max(x, y, hypotenuse)
				
						const cha = newL - this.startL;
				
						// 根据图片本身大小 决定每次改变大小的系数, 图片越大系数越小
						// 1px - 0.2
						let coe = 1;
						coe =
							coe / this.imageWidth > coe / this.imageHeight
								? coe / this.imageHeight
								: coe / this.imageWidth;
						coe = coe > 0.1 ? 0.1 : coe;
						const num = coe * cha;
				
						if (cha > 0) {
							scale += Math.abs(num);
						} else if (cha < 0) {
							scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale;
						}
				
						this.scale = scale;
					} else {
						const moveX = e.pageX - this.startX
						const moveY = e.pageY - this.startY
				
						this.x = moveX
						this.y = moveY
					}
				}
			},
            imgMoveing(e) {
				console.log('imgMoveing');
                if(this.scaling && e.touches.length == 2) {
                    let scale = this.oldScale

                    const x = e.touches[0].pageX - e.touches[1].pageX
                    const y = e.touches[0].pageY - e.touches[1].pageY
                    const hypotenuse = Math.sqrt(
                        Math.pow(x, 2) +
                        Math.pow(y, 2)
                    )

                    const newL = Math.max(x, y, hypotenuse)

                    const cha = newL - this.startL;

                    // 根据图片本身大小 决定每次改变大小的系数, 图片越大系数越小
                    // 1px - 0.2
                    let coe = 1;
                    coe =
                        coe / this.imageWidth > coe / this.imageHeight
                            ? coe / this.imageHeight
                            : coe / this.imageWidth;
                    coe = coe > 0.1 ? 0.1 : coe;
                    const num = coe * cha;

                    if (cha > 0) {
                        scale += Math.abs(num);
                    } else if (cha < 0) {
                        scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale;
                    }

                    this.scale = scale;
                } else {
                    const moveX = e.touches[0].pageX - this.startX
                    const moveY = e.touches[0].pageY - this.startY

                    this.x = moveX
                    this.y = moveY
                }
            },
            imgMoveEnd() {
				console.log('imgMoveEnd');
                setTimeout(() => {
                    this.scaling = false
					this.img_move = false;
                }, 100)
            },
			touchStart1(e,type) {
				if(type == 'crop_move'){
					this.crop_move = true;
					this.drag_move = false;
				}else{
					this.crop_move = false;
					this.drag_move = true;
				}
				this.knob_down = true;
				console.log('touchStart',111111111,e,e.pageX ,e.pageY );
			    this.startX = e.pageX - this.cropOffsertX;
			    this.startY = e.pageY - this.cropOffsertY;
				console.log(this.startX,this.startY);
			    this.cropOldW = this.cropW
			    this.cropOldH = this.cropH
			},
            touchStart(e) {
				console.log('touchStart');
                this.startX = e.touches[0].pageX - this.cropOffsertX;
                this.startY = e.touches[0].pageY - this.cropOffsertY;

                this.cropOldW = this.cropW
                this.cropOldH = this.cropH
            },
			 cropMoveing1(e) {
				 console.log(this.knob_down , !this.drag_move , this.crop_move);
				 if(this.knob_down && !this.drag_move && this.crop_move){
					 console.log('cropMoveing',e,this.startX,this.startY);
					 const moveX = this._cropX(e.pageX - this.startX)
					 const moveY = this._cropY(e.pageY - this.startY)
					 
					 this.cropOffsertX = moveX
					 this.cropOffsertY = moveY
					 console.log(99999,this.cropOffsertX, this.cropOffsertY);
				 }
				 
			 },
            cropMoveing(e) {
				console.log('cropMoveing');
                const moveX = this._cropX(e.touches[0].pageX - this.startX)
                const moveY = this._cropY(e.touches[0].pageY - this.startY)

                this.cropOffsertX = moveX
                this.cropOffsertY = moveY
            },
			dragMove1(e, type) {
				 console.log(this.knob_down , !this.drag_move , this.crop_move);
				console.log('dragMove',2222222,e,type);
			    if(this.cropFixed || !this.knob_down || !this.drag_move || this.crop_move) {
			        return false
			    }
			    const moveX = e.pageX - this.startX
			    const moveY = e.pageY - this.startY
			    switch (type) {
			        case 'left-top':
			            this._cropMoveLeft(moveX)
						if(!this.whScale){
							this._cropMoveTop(moveY)
						}
			            // 
			            break;
			        case 'middle-top':
					if(!this.whScale){
						this._cropMoveTop(moveY)
					}
			            break;
			        case 'right-top':
					if(this.whScale){
						this._cropMoveTop(moveY)
					}
			            this._cropMoveRight(moveX)
			            break;
			        case 'middle-right':
			            this._cropMoveRight(moveX)
			            break;
			        case 'right-bottom':
			            this._cropMoveRight(moveX)
						if(!this.whScale){
							this._cropMoveBottom(moveY)
						}
			            break;
			        case 'middle-bottom':
					if(!this.whScale){
						this._cropMoveBottom(moveY)
					}
			            break;
			        case 'left-bottom':
					if(!this.whScale){
						this._cropMoveBottom(moveY)
					}
			            this._cropMoveLeft(moveX)
			            break;
			        case 'middle-left':
			            this._cropMoveLeft(moveX)
			            break;
			        default:
			            break;
			    }
			},
            dragMove(e, type) {
				console.log('dragMove');
                if(this.cropFixed) {
                    return false
                }
                const moveX = e.touches[0].pageX - this.startX
                const moveY = e.touches[0].pageY - this.startY
                switch (type) {
                    case 'left-top':
                        this._cropMoveLeft(moveX)
						if(!this.whScale){
							this._cropMoveTop(moveY)
						}
                        // 
                        break;
                    case 'middle-top':
					if(!this.whScale){
						this._cropMoveTop(moveY)
					}
                        break;
                    case 'right-top':
					if(this.whScale){
						this._cropMoveTop(moveY)
					}
                        this._cropMoveRight(moveX)
                        break;
                    case 'middle-right':
                        this._cropMoveRight(moveX)
                        break;
                    case 'right-bottom':
                        this._cropMoveRight(moveX)
						if(!this.whScale){
							this._cropMoveBottom(moveY)
						}
                        break;
                    case 'middle-bottom':
					if(!this.whScale){
						this._cropMoveBottom(moveY)
					}
                        break;
                    case 'left-bottom':
					if(!this.whScale){
						this._cropMoveBottom(moveY)
					}
                        this._cropMoveLeft(moveX)
                        break;
                    case 'middle-left':
                        this._cropMoveLeft(moveX)
                        break;
                    default:
                        break;
                }
            },
            _cropMoveTop(y) {
				console.log('_cropMoveTop');
                const topY = this._cropY(y)
                this.cropH += this.cropOffsertY - topY
                this.cropOffsertY = topY
				if(this.whScale){
					this.cropW = this.cropH * 2
				}
            },
            _cropMoveRight(x) {
				console.log('_cropMoveRight');
                if(this.cropOldW + x >= this.windowWidth - this.border) {
                    return false;
                }
                this.cropW = this.cropOldW + (x  - this.cropOffsertX)
				if(this.whScale){
					this.cropH = this.cropW / this.whScale
				}
            },
            _cropMoveBottom(y) {
				console.log('_cropMoveBottom');
                if(this.cropOldH + y >= this.windowHeight - this.containerTop - this.border) {
                    return false;
                }
                this.cropH = this.cropOldH + (y  - this.cropOffsertY)
            },
            _cropMoveLeft(x) {
				console.log('_cropMoveLeft');
                const leftX = this._cropY(x)
                this.cropW += this.cropOffsertX - leftX
                this.cropOffsertX = leftX
				if(this.whScale){
					this.cropH = this.cropW / this.whScale
				}
            },
            _cropX(x) {
				console.log('_cropX',this.border,x,this.cropW,this.windowWidth);
                if(x <= this.border) {
                    return this.border
                }
                if(x + this.cropW >= this.windowWidth - this.border) {
                    return this.windowWidth - this.cropW - this.border
                }
                return x
            },
            _cropY(y) {
				console.log('_cropY',y,this.border,this.cropH,this.windowHeight,this.containerTop);
                if(y <= this.border) {
                    return this.border
                }
				console.log(this.windowHeight - this.containerTop - this.border,this.cropH,y);
                if(y  + this.cropH >= this.windowHeight - this.containerTop - this.border) {
				// if(y + this.cropH >= this.windowHeight - this.containerTop - this.border - 40) {
                    return this.windowHeight - this.cropH - this.containerTop - this.border - 42;
                }
                return y
            },
			toBase64(r) {
				let _this = this;
				return new Promise((resolve, reject) => {
					//#ifdef H5
					pathToBase64(r)
						.then(base64 => {
							resolve(base64);
						})
						.catch(error => {
							console.error(error)
						})
					//#endif
					//#ifdef MP-WEIXIN
					uni.getFileSystemManager().readFile({
						filePath: r, //选择图片返回的相对路径
						encoding: 'base64', //编码格式
						success: res => {
							let base64 = 'data:image/jpeg;base64,' + res.data
							resolve(base64);
						}
					});
					//#endif
					//#ifdef APP-PLUS
					pathToBase64(r)
						.then(base64 => {
							resolve(base64);
						})
						.catch(error => {
							console.error(error)
						})
					//#endif
				});
			},
        }
    }
</script>

<style scoped lang="css">

    @font-face {
        font-family: "iconfont";
        src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAR4AAsAAAAACKgAAAQsAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqEfIRGATYCJAMMCwgABCAFhG0HShugB8gOJUHBwAAAAAFEBNmwzd4dtatSmmpFoVAEhUThEAYkCozFKDCqCVO6RfH/89v869awDnTR1qrSANFt4GG4SNxreBn91fmV9f3+53J613ieHba+N1zmGM8PA7oXTaCAxpjei8IoLWFsGLu4jPME6vWJJdovqmgAO4U2LRBnep0K7GJmpYQWanXVOWuLuAFrtenK4haAa/f38QnKsCOpyrRFh6eFWsh5KXnfYcn958BGQNKfE8wmMmaAQpzkuo9Z+ukZluoltVV5abUipL5i/ysArlhWVut/eCRBVNPUjYg6oUo7JTHFoaYDSvdacnKTq9GAB4AY5y2dtL3qpFh1DENdnJC6Hq+xYb7pyRMDMzc/fYoJjY8flwO3m98rMucF+IZHj6Cagw5UeKpxyFbt2rHGY/8jpa7CYMvLfcIesLjY3bdqhaf+nqgQs2qT/+rjCH/VfA0VFGuAC3iE8NEr/Vau8vZsXiUy7+V3c3tQQXMAuNjDCC89KDIHH0OFhnUi81GEPwyc7wZUaN7DnUf4g+ZLQsMKYV/94NjK7R7TEM4niTY1oJ5zEU62aNVaasUub08YLUEam5EnT6a61/I17dNk+vTu9jpJjXhsTFwjqTtpCBxBIIgS6iQnc/Zod1YGKp0rAwsD8kkyP6AwcK0hcAwkiQmBhWvxPZWKDu86aUH2nLEdi9rGX1eXq5P6A1SrnAucMVMdZH/GKi/jyfCqJyucfK3mXpVujXOPfFf5LC4Dvx0X/943JyOq4HuCTZ8KiIPPAb6ro8akpT6ufiq39BQrNlk5mp8pO0JlJLk8f5QalRjoP60IMx0N8n7wGhSD3n6/F1zlcTVz/cR+Ev0lkLSTd7UiPbD/wCxGRMA2Krwro2O0bTQtImbwhjAJc0S3N4ROx15/PH60IzaIOjCbEelqkDOfETNxb/FMixnWNzeJp2KPQw9A5d76jGUOQOUvH7RE/o2RfkNatd3OGf9q0QKbnq8WB7qy+hVqJRjJn1BQgP/iErks0yy5iGJTrOayW7C/z0IoZH0qNH+7N+31XXc7G2p1hZDU6IWs1ghaqDNQpcEKVKu1BfWmFW9u0IFhKUodpswCEFodgqTZHWStbqOF+hqqdPsG1VrDEuodhfueDcZCj+QzuIrFtZh6BNNraIowbCzi1dbhOlOfionKXHoTzgzoY5hCKk/minEKZ/pYMDCoU7IsgREM3Y8Vgcvwvj4aMzK0AdewUpJljWkyGZH3IKmG7gfEHgZOhYXTwqiNwOhp0CiE3ZiFpL5fB6dj0keFKcGV+JvgGAP0vWMUpOQ10GI1VQt3LoMHDNJRYrEIPInAoPXDFEEnrk9P0zDG/FEGOA2WFNkiaZRGhuoRddXS8bX917cL6mn9c6TIUXSekybKHKQfJXFq2KSiRklLYU8dNKWDIX0cAA==') format('woff2');
    }
	.shade{
		width: 100%;
		height: 100%;
		position: fixed;
		background: rgba(0,0,0,0.2);
		left: 0;
		top: 0;
	}
    .vue-cropper {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 998;
        box-sizing: border-box;
        user-select: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        direction: ltr;
        touch-action: none;
        text-align: left;
        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
    }

    .cropper-canvas {
        position: absolute;
        top: -9999px;
        left:-9999px;
        z-index: -998;
    }

    .vue-cropper .uni-info__ft {
        position: absolute;
        line-height: 48px;
        font-size: 18px;
        display: -webkit-box;
        display: -webkit-flex;
        display: flex;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 998;
    }

    .btn-group {
        position: absolute;
        right: 30px;
        bottom: 78px;
        z-index: 998;
    }

    .btn-item {
        position: relative;
        width: 40rpx;
        height: 40rpx;
        background: #fff;
        border-radius: 20px;
        padding: 10px;
        display: inline-block;
        margin-left: 10px;
    }

    .btn-item:active {
        background: #ccc;
    }

    .rotate-btn {
        font-family: "iconfont" !important;
        font-size: 24px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        line-height: 20px;
    }

    .rotate-btn:before {
        content: "\e65c";
        margin-left: -2px;
    }

    .reset-btn {
        font-family: "iconfont" !important;
        font-size: 24px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        line-height: 20px;
    }

    .reset-btn:before {
        content: "\e648";
        margin-left: -2px;
    }

    .vue-cropper .uni-info__ft:after {
        content: " ";
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        height: 1px;
        border-top: 1px solid #d5d5d6;
        color: #d5d5d6;
        -webkit-transform-origin: 0 0;
        transform-origin: 0 0;
        -webkit-transform: scaleY(.5);
        transform: scaleY(.5);
        z-index: 998;
    }

    .vue-cropper .uni-modal__btn {
        display: block;
        -webkit-box-flex: 1;
        -webkit-flex: 1;
        flex: 1;
        color: #3cc51f;
        text-decoration: none;
        -webkit-tap-highlight-color: rgba(0,0,0,0);
        position: relative;
        text-align: center;
        background-color: #fff;
        z-index: 998;
		height: 80rpx;
		line-height: 80rpx;
    }

    .vue-cropper .uni-modal__btn:first-child:after { display:  none }
    .vue-cropper .uni-modal__btn:after {
        content: " ";
        position: absolute;
        left: 0;
        top: 0;
        width: 1px;
        bottom: 0;
        border-left: 1px solid #d5d5d6;
        color: #d5d5d6;
        -webkit-transform-origin: 0 0;
        transform-origin: 0 0;
        -webkit-transform: scaleX(.5);
        transform: scaleX(.5);
        z-index: 998;
    }

    .vue-cropper .uni-modal__btn:active {
        background-color: #eee;
    }

    .cropper-box,
    .cropper-box-canvas,
    .cropper-drag-box,
    .cropper-crop-box,
    .cropper-face {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        user-select: none;
        z-index: 998;
    }

    .uni-image {
        width: 100%;
        height: 100%;
    }

    .cropper-box-canvas image {
        position: relative;
        text-align: left;
        user-select: none;
        transform: none;
        max-width: none;
        max-height: none;
        z-index: 998;
    }

    .cropper-box {
        overflow: hidden;
    }

    .cropper-move {
        cursor: move;
    }

    .cropper-crop {
        cursor: crosshair;
    }

    .cropper-modal {
        background: rgba(0, 0, 0, 0.5);
    }

    .pointer-events {
        pointer-events:none;
    }

    .cropper-crop-box {
        /*border: 2px solid #39f;*/
    }

    .cropper-view-box {
        display: block;
        overflow: hidden;
        width: 100%;
        height: 100%;
        outline: 1px solid #39f;
        outline-color: rgba(51, 153, 255, 0.75);
        user-select: none;
    }

    .cropper-view-box image {
        user-select: none;
        text-align: left;
        max-width: none;
        max-height: none;
    }

    .cropper-face {
        top: 0;
        left: 0;
        background-color: #fff;
        opacity: 0.1;
    }

    .crop-line {
        position: absolute;
        display: block;
        width: 100%;
        height: 100%;
        opacity: 0.1;
        z-index: 998;
    }

    .line-w {
        top: -3px;
        left: 0;
        height: 5px;
        cursor: n-resize;
    }

    .line-a {
        top: 0;
        left: -3px;
        width: 5px;
        cursor: w-resize;
    }

    .line-s {
        bottom: -3px;
        left: 0;
        height: 5px;
        cursor: s-resize;
    }

    .line-d {
        top: 0;
        right: -3px;
        width: 5px;
        cursor: e-resize;
    }

    .crop-point {
        position: absolute;
        width: 8px;
        height: 8px;
        opacity: 0.75;
        background-color: #39f;
        border-radius: 100%;
        z-index: 998;
    }

    .point-lt {
        top: -4px;
        left: -4px;
        cursor: nw-resize;
    }

    .point-mt {
        top: -5px;
        left: 50%;
        margin-left: -3px;
        cursor: n-resize;
    }

    .point-rt {
        top: -4px;
        right: -4px;
        cursor: ne-resize;
    }

    .point-ml {
        top: 50%;
        left: -4px;
        margin-top: -3px;
        cursor: w-resize;
    }

    .point-mr {
        top: 50%;
        right: -4px;
        margin-top: -3px;
        cursor: e-resize;
    }

    .point-lb {
        bottom: -5px;
        left: -4px;
        cursor: sw-resize;
    }

    .point-mb {
        bottom: -5px;
        left: 50%;
        margin-left: -3px;
        cursor: s-resize;
    }

    .point-rb {
        bottom: -5px;
        right: -4px;
        cursor: se-resize;
    }
</style>

页面进行引用调用

<invinbg-image-cropper v-if="isOpenLogo" ref="logo" :src="tempFilePath" :isBase64="false" :whScale="0" :maxWidth="500" width="0" height="0" @confirm="imgUpload_logo" @cancel="cancel"></invinbg-image-cropper>

返回事项处理

data() {
	tempFilePath:'',
	isOpenLogo:false,
},
methods: {
	ChooseImage(e) {
		this.isOpenLogo = true;
		uni.chooseImage({
			count: 1, //默认9
			sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
			sourceType: ['album'], //从相册选择
			success: (res) => {
				if( typeof(res.tempFilePaths) == 'object'){
					this.tempFilePath = res.tempFilePaths[0]
				}else{
					this.tempFilePath = res.tempFilePaths
				}
			}
		});
	},
	imgUpload_logo(res){
		this.isOpenLogo = false;
		this.tempFilePath = '';
		let _this = this;
		uni.showLoading({
			title: '上传中...',
		})
		uni.uploadFile({
			url: url, //仅为示例,非真实的接口地址
			filePath:res,
			name: 'logo',
			success: (uploadres) => {
				uni.showToast({
					title: '上传成功',
					icon : 'none',
					duration:1500,
				});
				setTimeout(() => {
					console.log('进行相关操作');
				} ,1500)
			},complete:(uploadres)=>{
				uni.hideLoading();
			}
		});
	},
	cancel() {
		console.log('取消上传');
	},
}
延伸阅读
    发表评论