/**
|
* CImagePreview
|
* @author Tevin
|
*/
|
|
<template>
|
<view class="c-image-preview">
|
<image
|
class="c-image-preview-img"
|
:class="imgClass"
|
mode="aspectFit"
|
:lazyLoad="true"
|
v-for="(img, index) of imgList"
|
:src="loadFail[index] ? img.org : img.thumb"
|
:key="index"
|
@tap="evt => $preview({ current: img.org, urls: imgs })"
|
@error="evt => handleLoadError(index)"
|
/>
|
</view>
|
</template>
|
|
<script>
|
import Taro from '@tarojs/taro';
|
import { $ } from '@tarojs/extend';
|
import './cImagePreview.scss';
|
|
// 直线方程,点斜式参数
|
const createLineEquation = (p1, p2) => {
|
const k = (p1.y - p2.y) / (p1.x - p2.x);
|
const b = p1.y - k * p1.x;
|
return { k, b };
|
};
|
const winWidth = window.innerWidth;
|
|
export default {
|
name: 'CImagePreview',
|
props: {
|
// 图片样式名
|
imgClass: String,
|
// 图片地址
|
imgs: {
|
type: Array,
|
default: () => [],
|
},
|
// 开启缩略图地址转换
|
useThumb: {
|
typeof: Boolean,
|
default: false,
|
},
|
},
|
data() {
|
return {
|
loadFail: [],
|
};
|
},
|
computed: {
|
imgList() {
|
return this.imgs.map((img, index) => ({
|
org: img,
|
thumb: this.useThumb
|
? img.replace(/(.*?)(\.(png|jpg|jpeg|gif))$/, '$1_thumb$2')
|
: img,
|
}));
|
},
|
},
|
methods: {
|
handleLoadError(index) {
|
while (this.loadFail.length - 1 < index) {
|
this.loadFail.push(false);
|
}
|
this.loadFail.splice(index, 1, true);
|
},
|
// option { current, urls }
|
$preview(option) {
|
// 网页模式下,增加缩放操作
|
if (process.env.TARO_ENV === 'h5') {
|
Taro.previewImage({
|
...option,
|
success: () => {
|
this._bindZoomEvent();
|
option.success && option.success();
|
},
|
});
|
}
|
// 小程序模式,直接支持缩放
|
else {
|
Taro.previewImage({
|
current: option.current, // 当前显示图片的http链接
|
urls: option.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')) || 0;
|
startOffsetY = parseInt($img.css('top')) || 0;
|
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.k * scale + equationX.b;
|
const top = equationY.k * scale + equationY.b;
|
// 渲染
|
$img.css({
|
transform: 'scale(' + scale + ')',
|
left,
|
top,
|
});
|
}
|
},
|
touchend: evt => {
|
if (evt.touches.length == 0) {
|
zooming = false;
|
}
|
},
|
});
|
});
|
}, 100);
|
},
|
},
|
};
|
</script>
|