WebApp【公共组件库】@前端(For Git Submodule)
Tevin
2022-09-23 ec3f9f1abaf2b0327a69ac7b223120f594986d03
上传图片前预览,支持H5模式下的双指缩放
1 files added
1 files modified
172 ■■■■■ changed files
forms/imagePicker/CImagePicker.vue 6 ●●●● patch | view | raw | blame | history
forms/imagePicker/CImagePreview.vue 166 ●●●●● patch | view | raw | blame | history
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链接列表
            });
forms/imagePicker/CImagePreview.vue
New file
@@ -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>