<template> 
 | 
    <view class="settingHeadImage" @touchstart="onTouchstart" @touchmove.stop.prevent="onTouchmove" @touchend="touchE"> 
 | 
        <!-- 蒙层 --> 
 | 
        <canvas class="pre-canvas" canvas-id="firstCanvas" :style="{ width: 100 + 'vw', height: 100 + 'vh' }"></canvas> 
 | 
        <!-- img预览 --> 
 | 
        <view class="preImage" :style="{ width: preImgW + 'px' }"> 
 | 
            <canvas canvas-id="mycanvas" class="pre-i" 
 | 
                :style="{ width: preImgW + 'px', height: preImgH + 'px', transform: `translate(${x}px,${y}px)` }"></canvas> 
 | 
        </view> 
 | 
        <!-- 工具 --> 
 | 
        <view class="setting-btns"> 
 | 
            <!-- <text @click="onCrop">确定</text> --> 
 | 
            <u-button text="确定" @click="onCrop"></u-button> 
 | 
        </view> 
 | 
    </view> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
    export default { 
 | 
        data() { 
 | 
            return { 
 | 
                maxW: 250, // 最大宽度 
 | 
                maxH: 250, 
 | 
                screenWidth: '', // 屏幕宽 
 | 
                screenHeight: '', 
 | 
                xToTop: 0, // x方向距离顶部距离 
 | 
                scale: 1, // 缩放 
 | 
                preSrc: '', 
 | 
                preImgW: '', 
 | 
                preImgH: '', 
 | 
                x: 0, 
 | 
                y: 0, 
 | 
                oldx: 0, 
 | 
                oldy: 0, 
 | 
                isMove: false, 
 | 
                start: { 
 | 
                    left: 0, 
 | 
                    top: 0 
 | 
                } 
 | 
            }; 
 | 
        }, 
 | 
        computed: {}, 
 | 
        onLoad(option) { 
 | 
            // 选择照片信息 
 | 
            let data = JSON.parse(option.item); 
 | 
            console.log(data) 
 | 
            this.$nextTick(() => { 
 | 
                const query = uni.createSelectorQuery(); 
 | 
                query.select('.settingHeadImage').boundingClientRect(); 
 | 
                query.exec(res => { 
 | 
                    // 设置屏幕大小 
 | 
                    this.screenWidth = res[0].width; 
 | 
                    this.screenHeight = res[0].height; 
 | 
                    // 设置图像基准值,图像基准值按屏幕宽度设置,两边留白各40 
 | 
                    this.maxH = res[0].width - 80; 
 | 
                    this.maxW = res[0].width - 80; 
 | 
                    // 设置X轴值,算式:屏幕高度的一半减去基准框高度的一半 
 | 
                    this.xToTop = this.screenHeight / 2 - this.maxH / 2; 
 | 
                    this.setImageSize(data); 
 | 
                }); 
 | 
            }) 
 | 
        }, 
 | 
        methods: { 
 | 
            // 宽高处理 
 | 
            setImageSize(data) { 
 | 
                const { 
 | 
                    tempFilePath 
 | 
                } = data; 
 | 
                const { 
 | 
                    maxH, 
 | 
                    maxW 
 | 
                } = this; 
 | 
                uni.getImageInfo({ 
 | 
                    src: tempFilePath, 
 | 
                    success: res => { 
 | 
                        const { 
 | 
                            errMsg, 
 | 
                            path, 
 | 
                            width, 
 | 
                            height 
 | 
                        } = res; 
 | 
                        let w = ''; 
 | 
                        let h = ''; 
 | 
                        if (errMsg === 'getImageInfo:ok') { 
 | 
                            w = width; 
 | 
                            h = height; 
 | 
                            // 宽大与高大于最大宽度 
 | 
                            if (width > height && width > maxW) { 
 | 
                                w = Math.floor((width / height) * maxW); 
 | 
                                h = maxH; 
 | 
                            } 
 | 
                            // 高大于宽大于最大高度 
 | 
                            if (height > width && height > maxH) { 
 | 
                                h = Math.floor((height / width) * maxH); 
 | 
                                w = maxW; 
 | 
                            } 
 | 
                            // 宽高相等或者宽高小于最大值 
 | 
                            if (width === height || (width < maxW && height < maxH)) { 
 | 
                                h = maxH; 
 | 
                                w = maxW; 
 | 
                            } 
 | 
                            this.preSrc = path; 
 | 
                            this.preImgH = h; 
 | 
                            this.preImgW = w; 
 | 
                            // 设置蒙层 
 | 
                            this.setBgBox(); 
 | 
                            setTimeout(() => { 
 | 
                                // 图像预览 
 | 
                                this.previewCanvas({ 
 | 
                                    w, 
 | 
                                    h, 
 | 
                                    path 
 | 
                                }); 
 | 
                            }, 500) 
 | 
                        } 
 | 
                    } 
 | 
                }); 
 | 
            }, 
 | 
  
 | 
            // 设置蒙层 
 | 
            setBgBox() { 
 | 
                const { 
 | 
                    maxW, 
 | 
                    maxH, 
 | 
                    screenHeight, 
 | 
                    screenWidth, 
 | 
                    xToTop 
 | 
                } = this; 
 | 
                const ctx = uni.createCanvasContext('firstCanvas'); 
 | 
                // 先清除矩形 
 | 
                ctx.clearRect(0, 0, screenWidth, screenHeight); 
 | 
                // 设置canvas透明度 
 | 
                ctx.setGlobalAlpha(0.7); 
 | 
                // 设置蒙层颜色 
 | 
                ctx.setFillStyle('#000000'); 
 | 
                // 绘制蒙层 
 | 
                ctx.fillRect(0, 0, screenWidth, screenHeight); 
 | 
                // 基准框留白 
 | 
                ctx.clearRect(40, xToTop, maxW, maxH); 
 | 
                // 绘制基准框 
 | 
                ctx.beginPath(); 
 | 
                ctx.setStrokeStyle('#FFFFFF'); 
 | 
                ctx.strokeRect(40, xToTop, maxW, maxH); 
 | 
                ctx.closePath(); 
 | 
                ctx.draw(); 
 | 
            }, 
 | 
            // 预览 
 | 
            previewCanvas({ 
 | 
                w, 
 | 
                h, 
 | 
                path 
 | 
            }) { 
 | 
                console.log(path, w, h) 
 | 
                const ctx = uni.createCanvasContext('mycanvas'); 
 | 
                ctx.drawImage(path, 0, 0, w, h); 
 | 
                ctx.draw(); 
 | 
            }, 
 | 
            onTouchstart(ev) { 
 | 
                if (ev.changedTouches.length === 1) { 
 | 
                    this.isMove = true; 
 | 
                    this.start.left = ev.changedTouches[0].clientX; 
 | 
                    this.start.top = ev.changedTouches[0].clientY; 
 | 
                } 
 | 
            }, 
 | 
            onTouchmove(ev) { 
 | 
                const { 
 | 
                    maxW, 
 | 
                    maxH, 
 | 
                    preImgH, 
 | 
                    preImgW, 
 | 
                    xToTop 
 | 
                } = this; 
 | 
                if (this.isMove && ev.changedTouches.length === 1) { 
 | 
                    let clientX = ev.changedTouches[0].clientX, 
 | 
                        clientY = ev.changedTouches[0].clientY; 
 | 
                    this.x = preImgW <= maxW ? 0 : this.oldx + clientX - this.start.left; 
 | 
                    this.y = preImgH <= maxH ? 0 : this.oldy + clientY - this.start.top; 
 | 
                } 
 | 
            }, 
 | 
            touchE(val) { 
 | 
                const { 
 | 
                    preImgH, 
 | 
                    preImgW, 
 | 
                    maxH, 
 | 
                    maxW 
 | 
                } = this; 
 | 
                const query = uni.createSelectorQuery(); 
 | 
                const fx = this.x; 
 | 
                query.select('.pre-i').boundingClientRect(); 
 | 
                query.exec(res => { 
 | 
                    // x、y回弹计算 
 | 
                    let y = (res[0].height - res[0].width) / 2; 
 | 
                    /** 
 | 
                     * 判断照片可移动的距离是否大于留白的值,如果大于向右划时图片的宽减去基准框的宽减去留白向左时留白,小于时按图片的可移动值 
 | 
                     * */ 
 | 
                    let x = (preImgW - maxW) / 2 > 40 ? (fx < 0 ? preImgW - maxW - 40 : 40) : (preImgW - maxW) / 2; 
 | 
                    if (preImgH > maxH) { 
 | 
                        this.y = this.y > y ? y : this.y < -y ? -y : this.y; 
 | 
                    } 
 | 
                    if (preImgW > maxW) { 
 | 
                        this.x = this.x > x ? x : this.x < -x ? -x : this.x; 
 | 
                    } 
 | 
                    this.oldx = this.x; 
 | 
                    this.oldy = this.y; 
 | 
                    this.isMove = false; 
 | 
                }); 
 | 
            }, 
 | 
            // 裁剪 
 | 
            onCrop() { 
 | 
                let y = 0; 
 | 
                let x = 0; 
 | 
                const query = uni.createSelectorQuery(); 
 | 
                query.select('.pre-i').boundingClientRect(); 
 | 
                query.exec(res => { 
 | 
                    // 获取预览img距离左上的距离 
 | 
                    y = Math.abs(res[0].top); 
 | 
                    x = Math.abs(res[0].left); 
 | 
                    const { 
 | 
                        maxW, 
 | 
                        maxH, 
 | 
                        preImgH, 
 | 
                        preImgW, 
 | 
                        xToTop 
 | 
                    } = this; 
 | 
                    uni.canvasToTempFilePath({ 
 | 
                        x: Math.abs(res[0].left < 0 ? x + 40 : x - 40), 
 | 
                        y: Math.abs(res[0].top < 0 ? xToTop + y : xToTop - y), 
 | 
                        width: maxW, 
 | 
                        height: maxH, 
 | 
                        destWidth: maxW, 
 | 
                        destHeight: maxH, 
 | 
                        canvasId: 'mycanvas', 
 | 
                        success: fileRes => { 
 | 
                            uni.$emit('update', fileRes) 
 | 
                            uni.navigateBack({ delta: 1 }); 
 | 
                        }, 
 | 
                        fail: function(err) { 
 | 
                            uni.showToast({ 
 | 
                                title: '上传失败:图片生成过程中遇到错误', 
 | 
                                icon: 'none' 
 | 
                            }); 
 | 
                        } 
 | 
                    }); 
 | 
                }); 
 | 
            } 
 | 
        } 
 | 
    }; 
 | 
</script> 
 | 
  
 | 
<style lang="scss" scoped> 
 | 
    .settingHeadImage { 
 | 
        background-color: #000000; 
 | 
        overflow: hidden; 
 | 
  
 | 
        .pre-canvas { 
 | 
            position: fixed; 
 | 
            top: 0; 
 | 
            left: 0; 
 | 
            z-index: 20; 
 | 
        } 
 | 
  
 | 
        .preImage { 
 | 
            min-width: 100vw; 
 | 
            height: 100vh; 
 | 
            display: flex; 
 | 
            justify-content: center; 
 | 
            align-items: center; 
 | 
            overflow: hidden; 
 | 
            z-index: 1; 
 | 
  
 | 
            .pre-i { 
 | 
                // transition: all 0.1s; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        .setting-btns { 
 | 
            position: fixed; 
 | 
            bottom: 0; 
 | 
            left: 0; 
 | 
            z-index: 20; 
 | 
            font-size: 14px; 
 | 
            width: 100%; 
 | 
            color: #ffffff; 
 | 
        } 
 | 
    } 
 | 
</style> 
 |