From ec3f9f1abaf2b0327a69ac7b223120f594986d03 Mon Sep 17 00:00:00 2001
From: Tevin <tingquanren@163.com>
Date: Fri, 23 Sep 2022 20:48:38 +0800
Subject: [PATCH] 上传图片前预览,支持H5模式下的双指缩放

---
 forms/imagePicker/CImagePicker.vue  |    6 +
 forms/imagePicker/CImagePreview.vue |  166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+), 1 deletions(-)

diff --git a/forms/imagePicker/CImagePicker.vue b/forms/imagePicker/CImagePicker.vue
index 6ebd882..fc22f85 100644
--- a/forms/imagePicker/CImagePicker.vue
+++ b/forms/imagePicker/CImagePicker.vue
@@ -25,6 +25,7 @@
             :onImageClick="(index, file)=>handleImgView(index,file)"
         />
         <CImageCompressor ref="compressor" />
+        <CImagePreview ref="imgPreview" />
     </view>
 </template>
 
@@ -36,12 +37,14 @@
 import { $fetchCommon } from '@fetchers/FCommon';
 import { Tools } from '@components/common/Tools';
 import CImageCompressor from './CImageCompressor.vue';
+import CImagePreview from './CImagePreview.vue';
 import './cImagePicker.scss';
 
 export default {
     name: 'CImagePicker',
     components: {
         CImageCompressor,
+        CImagePreview,
         AtInput,
         AtImagePicker,
         AtCurtain,
@@ -158,7 +161,8 @@
             const urls = this.files
                 .map(file => (file.type === 'btn' ? false : file.url))
                 .filter(Boolean);
-            Taro.previewImage({
+            // 图片预览,支持H5模式下的双指缩放
+            this.$refs.imgPreview.$preview({
                 current: file.url, // 当前显示图片的http链接
                 urls, // 需要预览的图片http链接列表
             });
diff --git a/forms/imagePicker/CImagePreview.vue b/forms/imagePicker/CImagePreview.vue
new file mode 100644
index 0000000..cb615de
--- /dev/null
+++ b/forms/imagePicker/CImagePreview.vue
@@ -0,0 +1,166 @@
+/**
+ * CImagePreview
+ * @author Tevin
+ */
+
+<template>
+    <view class="c-image-preview"></view>
+</template>
+
+<script>
+import Taro from '@tarojs/taro';
+import { $ } from '@tarojs/extend';
+
+// 直线方程,点斜式参数
+const createLineEquation = (p1, p2) => ({
+    k: (p1.y - p2.y) / (p1.x - p2.x),
+    b: p1.y - k * p1.x,
+});
+const winWidth = window.innerWidth;
+
+export default {
+    name: 'CImagePreview',
+    data() {
+        return {};
+    },
+    methods: {
+        $preview(option) {
+            // 网页模式下,增加缩放操作
+            if (process.env.TARO_ENV === 'h5') {
+                Taro.previewImage({
+                    ...option,
+                    success: () => {
+                        this._bindZoomEvent();
+                        option.success && option.success();
+                    },
+                });
+            }
+            // 小程序模式,直接支持缩放
+            else {
+                Taro.previewImage({
+                    current: file.url, // 当前显示图片的http链接
+                    urls, // 需要预览的图片http链接列表
+                });
+            }
+        },
+        _bindZoomEvent() {
+            const $previewImage = $('.preview-image');
+            setTimeout(() => {
+                $previewImage.find('.swiper-slide').css({ overflow: 'hidden' });
+                $previewImage.find('img').each((idx, elm) => {
+                    const $img = $(elm);
+                    const defaultWidth = elm.width;
+                    $img.css({
+                        width: defaultWidth,
+                        maxWidth: '',
+                        position: 'relative',
+                    });
+                    let startX = 0;
+                    let startY = 0;
+                    let startOffsetX = 0;
+                    let startOffsetY = 0;
+                    let startWidth = 0;
+                    let zooming = false;
+                    let distance = 0;
+                    let scale = 1;
+                    let equationX = {};
+                    let equationY = {};
+                    $img.on({
+                        touchstart: evt => {
+                            startOffsetX = parseInt($img.css('left'));
+                            startOffsetY = parseInt($img.css('top'));
+                            startWidth = parseInt($img.css('width')) * scale;
+                            if (evt.touches.length == 1) {
+                                const { clientX, clientY } = evt.touches[0];
+                                startX = clientX;
+                                startY = clientY;
+                            } else {
+                                const xMove =
+                                    evt.touches[1].clientX - evt.touches[0].clientX;
+                                const yMove =
+                                    evt.touches[1].clientY - evt.touches[0].clientY;
+                                distance = Math.sqrt(xMove * xMove + yMove * yMove);
+                                zooming = true;
+                                // 已放大过了
+                                if (scale - 1 > 0.1) {
+                                    equationX = createLineEquation(
+                                        { x: 1, y: 0 },
+                                        { x: scale, y: startOffsetX }
+                                    );
+                                    equationY = createLineEquation(
+                                        { x: 1, y: 0 },
+                                        { x: scale, y: startOffsetY }
+                                    );
+                                }
+                                // 初始状态,不线性计算
+                                else {
+                                    equationX = equationY = { k: 0, b: 0 };
+                                }
+                            }
+                        },
+                        touchmove: evt => {
+                            if (evt.touches.length == 1) {
+                                //单指移动,缩放状态,不处理单指
+                                if (zooming) {
+                                    return;
+                                }
+                                const { clientX, clientY } = evt.touches[0];
+                                const left = clientX - startX + startOffsetX;
+                                const top = clientY - startY + startOffsetY;
+                                // 限制大小
+                                const limitSize = (startWidth - winWidth) / 2;
+                                // 在限制大小范围内,移动图片自身
+                                if (left >= -limitSize && left <= limitSize) {
+                                    $img.css({ top, left });
+                                    // 阻止冒泡
+                                    evt.preventDefault();
+                                    evt.stopPropagation();
+                                }
+                                // 超出限制大小不操作,冒泡翻页
+                                else {
+                                }
+                            } else {
+                                //双指缩放
+                                const xMove =
+                                    evt.touches[1].clientX - evt.touches[0].clientX;
+                                const yMove =
+                                    evt.touches[1].clientY - evt.touches[0].clientY;
+                                const newDistance = Math.sqrt(
+                                    xMove * xMove + yMove * yMove
+                                );
+                                const distanceDiff = newDistance - distance;
+                                const newScale = scale + 0.01 * distanceDiff;
+                                // 缩放比例设置
+                                if (newScale <= 5 && newScale >= 1) {
+                                    distance = newDistance;
+                                    scale = newScale;
+                                } else {
+                                    if (newScale > 5) {
+                                        scale = 5;
+                                    } else if (newScale < 1) {
+                                        scale = 1;
+                                    }
+                                }
+                                // 修正位置
+                                const left = equationX.a * scale + equationX.b;
+                                const top = equationY.a * scale + equationY.b;
+                                // 渲染
+                                $img.css({
+                                    transform: 'scale(' + scale + ')',
+                                    left,
+                                    top,
+                                });
+                            }
+                        },
+                        touchend: evt => {
+                            if (evt.touches.length == 0) {
+                                zooming = false;
+                            }
+                        },
+                    });
+                });
+            }, 100);
+        },
+    },
+};
+</script>
\ No newline at end of file

--
Gitblit v1.9.1