uniapp小程序模板图片

273 阅读4分钟

回顾

要求开发一个模板图片,上传图片,可以对图片移动,缩放,保存到本地

总结

canvas movable-view 问题

  1. 首先想法是canvas移动缩放.不能移动canvas移动在真机和开发工具是不一样的,
    • 他的touchas对象中没有pageX,pageY。
    • 他的touchart数组会发生一些变化
    • 双指之后和一些不明原因会导致移动位置不准确,
  1. movable-view 移动缩放问题不大,
    • 但有时也会不灵,差异不大,
    • 但是不能保存到本地
    • movable-area父元素没有这个也不会有效果

2.解决方案,两者结合,

注意、

1.canvas位置要定位到页面之外,不然会对页面有影响,

2.小程序要申请相应的隐私权限,拍照,相册等。

3.canvas 配置项,宽高要与页面的这种层和movable-view 相同 ctx.translate(x,y)canvase位置和movable-view移动的位置相同ctx.scale(scale,scale)与缩放的倍数相同

4.canvas保存本地时要加延时器确保能够正常保存图片

5.movable-view 事件用到chang和scale事件注意的是scale事件x,y也会发生变化,所以事件中更改三个值。 5.背景图想要子啊moveble-view上又不影响他的操作需要定位后加一个 pointer-events: none;让他不会触发事件

<template>
    <view>

        <view class="img_box">
          //遮罩层
            <view class="img_zhe">
                <image src="../static/mbg.png" class="imag"></image>
            </view>
            <movable-area style="width: 100%;height: 1200rpx;  overflow: hidden;">
                <movable-view :x="x" :y="y" direction="all" @change="onChange" style="width: 100%;height: 1200rpx;"
                    :scale="true" @scale="scaleChange" scale-min="0.5" scale-max="3" scale-value="0.9">
                    <image :src="tempImagePath" class="imag" style="width: 100%;height: 100%"></image>
                </movable-view>
            </movable-area>

        </view>
        <view>
            <view class="flex">
                <view class="flex_item">
                    <view class="item_b">{{ '运动小将' }}</view>
                    <view class="item_g">{{ '订单类型' }}</view>
                </view>
                <view class="line">

                </view>

                <view class="flex_item">
                    <view class="item_b">{{ '5元' }}</view>
                    <view class="item_g">{{ '购买金额' }}</view>
                </view>
                <view class="line">

                </view>
                <view class="flex_item">
                    <view class="item_b">{{ '5分钟' }}</view>
                    <view class="item_g">{{ '骑行时常' }}</view>
                </view>
            </view>
            <view class="flex buttom">
                <button class="btn" @click="takePhoto">拍照</button>
                <button class="btn" @click="upImg">本地图片</button>
                <button class=" btn save" @click="captureAndSave">保存图片</button>
            </view>
        </view>
        <canvas class="canvs" canvas-id="bacbackground" ref="canvas"
            :style="'width:750rpx;height:1200rpx; bacbackground-color:#333'"></canvas>
    </view>
</template>
  
<script>
export default {
    data() {
        return {
            tempImagePath: '', // 存储临时图片路径
            canvasWidth: 0, // 画布宽度
            canvasHeight: 0, // 画布高度
            img: null, // 图片对象
            scale: 0.9,
            translateX: 0, // X轴偏移
            translateY: 0, // Y轴偏移
            touchStart: { x: 0, y: 0 }, // 触摸起始点
            touchMove: { x: 0, y: 0 }, // 触摸移动点
            isTouching: false, // 是否正在触摸
            ctx: null, // canvas 2d 上下文
            backgroundImagePath: '../static/mbg.png',
            initialPinchDistance: 0,
            pinch: false,//双指
            initialDistance: 0,
            clear: 0,
            x: 0,
            y: 0,
        };
    },
    methods: {

        upImg() {
            // 选择本地图片
            uni.chooseImage({
                count: 1,
                sizeType: ['compressed'],
                sourceType: ['album'],
                success: (res) => {
                    const tempFilePath = res.tempFilePaths[0];

                    // 更新页面或其他操作
                    this.tempImagePath = tempFilePath;
                    console.log('选择的本地图片路径:', tempFilePath);
                },
            });
        },
        onChange(event) {
            console.log('change', event)
            this.translateX = event.detail.x
            this.translateY = event.detail.y

        },
        scaleChange(event) {
            console.log('scale', event)
            this.translateX = event.detail.x
            this.translateY = event.detail.y
            this.scale = event.detail.scale

        },
        takePhoto() {
            // 选择图片
            uni.chooseImage({
                count: 1,
                sizeType: ['compressed'],
                sourceType: ['camera'],
                success: (res) => {
                    const tempFilePaths = res.tempFilePaths;
                    // 将临时图片路径存储在 data 中
                    this.tempImagePath = tempFilePaths[0];
                },
            });
        },
        initCanvas() {
            // 获取图片信息
            uni.getImageInfo({
                src: this.tempImagePath,
                success: (info) => {
                    // 计算画布大小,使用画布的大小作为背景图片的大小
                    this.canvasWidth = uni.upx2px(750); // 100upx
                    this.canvasHeight = uni.upx2px(1200); // 1200upx
                    // 初始化 canvas 上下文
                    // 初始化画布
                    this.drawCanvas();
                },
            });
        },
        drawCanvas() {
            //
            console.log('画布更新了')
            // 清空画布
            this.ctx = null
            this.ctx = uni.createCanvasContext('bacbackground', this);
            this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);

            // 设置图片的位置和缩放
            this.ctx.translate(this.translateX, this.translateY);
            this.ctx.scale(this.scale, this.scale);
            // 旋转图片
            this.ctx.rotate((this.clear * Math.PI) / 180);

            // 绘制拍照的图片
            this.ctx.drawImage(this.tempImagePath, 0, 0, this.canvasWidth, this.canvasHeight);
            // // 重置变换矩阵,确保接下来的操作不影响之前绘制的图片
            this.ctx.setTransform(1, 0, 0, 1, 0, 0);

            // 绘制背景图片
            this.ctx.drawImage(
                this.backgroundImagePath,
                0,
                0,
                this.canvasWidth,
                this.canvasHeight
            );

            // 将绘制的内容显示到画布上
            this.ctx.draw();
            setTimeout(() => {
                this.fopush()
            }, 100);
        },
        captureAndSave() {
            if (this.tempImagePath) {
                this.initCanvas()
            } else {
                uni.showToast({
                    title: '请先上传图片',
                    icon: 'none',
                    duration: 2000,
                });
            }

        },
        fopush() {
            return new Promise((resolve, reject) => {
                // 将 canvas 截图生成临时文件路径
                uni.canvasToTempFilePath({
                    canvasId: 'bacbackground', // canvas-id
                    success: (res) => {
                        // 保存成功,res.tempFilePath 是保存到本地的路径
                        const tempFilePath = res.tempFilePath;

                        // 保存到相册
                        uni.saveImageToPhotosAlbum({
                            filePath: tempFilePath,
                            success: () => {
                                uni.showToast({
                                    title: '保存成功',
                                    icon: 'success',
                                    duration: 2000,
                                });
                                resolve(tempFilePath);
                            },
                            fail: (err) => {
                                uni.showToast({
                                    title: '保存失败',
                                    icon: 'none',
                                    duration: 2000,
                                });
                                reject(err);
                            },
                        });
                    },
                    fail: (err) => {
                        console.error(err);
                        uni.showToast({
                            title: '截图失败',
                            icon: 'none',
                            duration: 2000,
                        });
                        reject(err);
                    },
                });
            });
        }

    },
};
</script>
<style lang="scss" scoped>
.img_box {
    height: 1200rpx;
    position: relative;
}

.canvs {
    position: absolute;
    top: 0;
    left: -1200rpx;
    pointer-events: none;
}

.btn_slider {
    width: 50%;
    display: flex;
    align-items: center;
}

.imag {
    width: 100%;
    height: 1200rpx;
}

.buttom_btn {
    display: flex;
    // margin: 10 30rpx;
    font-size: 35rpx;
    // border: 2rpx solid red;
    padding: 10rpx 30rpx;
}

::v-deep .u-number-box__plus {
    width: 80rpx !important;
}

/* 将 canvas 隐藏在页面外 */
// canvas {
//     position: absolute;
//     top: 0;
//     left: 0;

// }

.flex {
    margin-top: 10rpx;
    display: flex;
    justify-content: space-between;
    padding: 10rpx;
    height: 80rpx;


    .item_b {
        font-size: 30rpx;
        font-weight: bold;
    }

    .item_g {
        font-size: 25rpx;
        color: #9a9a9a;

    }

    .flex_item {
        width: 200rpx;
        text-align: center;
        padding: 10rpx;
    }

    .line {
        width: 2rpx;
        background-color: #333;
    }
}

.img_zhe {
    width: 100%;
    height: 1200rpx;
    position: absolute;

    top: 0;
    left: 0;
    z-index: 99;
    pointer-events: none;

    image {
        width: 100%;
        height: 100%;
    }
}



.btn {
    font-size: 30rpx;
    width: 250rpx;
    border-radius: 50rpx;
    background: white;
    box-sizing: border-box;
    border: 2rpx solid #9a9a;
}
</style>