@nutui/nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
254 lines (253 loc) • 10.8 kB
JavaScript
import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
import { _ as _object_without_properties } from "@swc/helpers/_/_object_without_properties";
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
import React, { useEffect, useRef, useState } from "react";
import Taro from "@tarojs/taro";
import { Video as TaroVideo, View } from "@tarojs/components";
import classNames from "classnames";
import { Close } from "@nutui/icons-react-taro";
import Popup from "../popup/index";
import Image from "../image/index";
import Swiper from "../swiper/index";
import SwiperItem from "../swiperitem/index";
import { ComponentDefaults } from "../../utils/typings";
import { usePropsValue } from "../../hooks/use-props-value";
import { mergeProps } from "../../utils";
var defaultProps = _object_spread_props(_object_spread({}, ComponentDefaults), {
images: [],
videos: [],
visible: false,
autoPlay: false,
defaultValue: 1,
closeOnContentClick: false,
pagination: true,
indicator: false,
indicatorColor: '#fff',
closeIcon: false,
closeIconPosition: 'top-right',
showMenuByLongpress: false,
onChange: function() {},
onClose: function() {}
});
export var ImagePreview = function(props) {
var _mergeProps = mergeProps(defaultProps, props), value = _mergeProps.value, className = _mergeProps.className, style = _mergeProps.style, images = _mergeProps.images, videos = _mergeProps.videos, visible = _mergeProps.visible, defaultValue = _mergeProps.defaultValue, indicatorColor = _mergeProps.indicatorColor, pagination = _mergeProps.pagination, indicator = _mergeProps.indicator, autoPlay = _mergeProps.autoPlay, loop = _mergeProps.loop, closeOnContentClick = _mergeProps.closeOnContentClick, closeIcon = _mergeProps.closeIcon, closeIconPosition = _mergeProps.closeIconPosition, showMenuByLongpress = _mergeProps.showMenuByLongpress, onClose = _mergeProps.onClose, onChange = _mergeProps.onChange, rest = _object_without_properties(_mergeProps, [
"value",
"className",
"style",
"images",
"videos",
"visible",
"defaultValue",
"indicatorColor",
"pagination",
"indicator",
"autoPlay",
"loop",
"closeOnContentClick",
"closeIcon",
"closeIconPosition",
"showMenuByLongpress",
"onClose",
"onChange"
]);
var classPrefix = 'nut-imagepreview';
var ref = useRef(null);
var _usePropsValue = _sliced_to_array(usePropsValue({
value: value,
defaultValue: defaultValue,
finalValue: defaultValue,
onChange: onChange
}), 2), innerNo = _usePropsValue[0], setInnerNo = _usePropsValue[1];
var _useState = _sliced_to_array(useState(visible), 2), showPop = _useState[0], setShowPop = _useState[1];
var _useState1 = _sliced_to_array(useState(0), 2), active = _useState1[0], setActive = _useState1[1];
var _useState2 = _sliced_to_array(useState(images.length + videos.length), 2), maxNo = _useState2[0], setMaxNo = _useState2[1];
var _useState3 = _sliced_to_array(useState({
scale: 1,
moveable: false,
oriDistance: 0,
originScale: 1
}), 2), store = _useState3[0], setStore = _useState3[1];
var lastTouchEndTime = useRef(0) // 用来辅助监听双击
;
var onTouchStart = function(event) {
var touches = event.touches;
var events = touches[0];
var events2 = touches[1];
// 如果已经放大,双击应变回原尺寸;如果是原尺寸,双击应放大
var curTouchTime = Date.now();
if (curTouchTime - lastTouchEndTime.current < 100) {
var store1 = store;
store1.scale = store1.scale === 1 ? 2 : 1;
scaleNow();
}
var store11 = store;
store11.moveable = true;
if (events2) {
// 如果开始两指操作,记录初始时刻两指间的距离
store11.oriDistance = getDistance(events, events2);
}
// 取到开始两指操作时的放大(缩小比例),store.scale 存储的是当前的放缩比(相对于标准大小 scale 为 1 的情况的放大缩小比)
store11.originScale = store11.scale;
};
var onTouchMove = function(event) {
if (!store.moveable) return;
var touches = event.touches;
var events = touches[0];
var events2 = touches[1];
var store1 = store;
// 双指移动
if (events2) {
var curDistance = getDistance(events, events2);
/** 此处计算倍数,距离放大(缩小) k 倍则 scale 也 扩大(缩小) k 倍。距离放大(缩小)倍数 = 结束时两点距离 除以 开始时两点距离
* 注意此处的 scale 变化是基于 store.scale 的。
* store.scale 是一个暂存值,比如第一次放大 2 倍,则 store.scale 为 2。
* 再次两指触碰的时候,store.originScale 就为 store.scale 的值,基于此时的 store.scale 继续放大缩小。 * */ var curScale = curDistance / store1.oriDistance;
// 最大放大 3 倍,缩小后松手要弹回原比例
store1.scale = Math.min(store1.originScale * curScale, 3);
scaleNow();
}
};
var onTouchEnd = function() {
lastTouchEndTime.current = Date.now();
var store1 = store;
store1.moveable = false;
if (store1.scale < 1.1 && store1.scale > 1 || store1.scale < 1) {
store1.scale = 1;
scaleNow();
}
};
useEffect(function() {
init();
}, []);
var init = function() {
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
document.addEventListener('touchcancel', onTouchEnd);
return function() {
document.removeEventListener('touchcancel', onTouchEnd);
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
};
};
useEffect(function() {
setShowPop(visible);
}, [
visible
]);
useEffect(function() {
setInnerNo(defaultValue || 1);
}, [
defaultValue
]);
useEffect(function() {
setActive(innerNo);
}, [
innerNo
]);
useEffect(function() {
setMaxNo(images.length + videos.length);
}, [
images,
videos
]);
var scaleNow = function() {
if (ref.current) {
ref.current.style.transform = "scale(".concat(store.scale, ")");
}
};
var getDistance = function(first, second) {
return Math.hypot(Math.abs(second.pageX - first.pageX), Math.abs(second.pageY - first.pageY));
};
var slideChangeEnd = function(page) {
setActive(page + 1);
onChange === null || onChange === void 0 ? void 0 : onChange(page + 1);
};
var onCloseInner = function(e) {
e.stopPropagation();
setShowPop(false);
setActive(innerNo);
scaleNow();
onClose === null || onClose === void 0 ? void 0 : onClose();
setStore(_object_spread_props(_object_spread({}, store), {
scale: 1
}));
};
var closeOnImg = function(e) {
e.stopPropagation();
// 点击内容区域的图片是否可以关闭弹层(视频区域由于nut-video做了限制,无法关闭弹层)
if (closeOnContentClick) onCloseInner(e);
};
return /*#__PURE__*/ React.createElement(Popup, {
visible: showPop,
className: "".concat(classPrefix, "-pop"),
onClick: onCloseInner
}, /*#__PURE__*/ React.createElement(View, {
className: classNames(classPrefix, className),
style: style,
ref: ref,
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
onTouchCancel: onTouchEnd
}, /*#__PURE__*/ React.createElement(Swiper, {
autoplay: autoPlay,
loop: loop,
direction: "horizontal",
className: "".concat(classPrefix, "-swiper"),
height: "100%",
style: {
display: showPop ? 'block' : 'none',
'--nutui-indicator-color': indicatorColor,
width: '100%',
height: '100%'
},
onChange: function(e) {
return slideChangeEnd(e.detail.current);
},
defaultValue: innerNo && (innerNo > maxNo ? maxNo - 1 : innerNo - 1),
indicator: indicator
}, _to_consumable_array(videos.map(function(item) {
return {
type: 'video',
data: item
};
})).concat(_to_consumable_array(images.map(function(item) {
return {
type: 'image',
data: item
};
}))).sort(function(a, b) {
var _a_data, _b_data;
var _a_data_index, _b_data_index;
return ((_a_data_index = (_a_data = a.data) === null || _a_data === void 0 ? void 0 : _a_data.index) !== null && _a_data_index !== void 0 ? _a_data_index : 0) - ((_b_data_index = (_b_data = b.data) === null || _b_data === void 0 ? void 0 : _b_data.index) !== null && _b_data_index !== void 0 ? _b_data_index : 0);
}).map(function(item, index) {
return /*#__PURE__*/ React.createElement(SwiperItem, {
key: index,
className: "nut-imagepreview-swiper-item"
}, item.type === 'video' ? /*#__PURE__*/ React.createElement(TaroVideo, {
src: item.data.source.src,
onClick: closeOnImg,
controls: item.data.options.controls,
autoplay: false,
loop: false,
muted: item.data.options.muted
}) : /*#__PURE__*/ React.createElement(Image, _object_spread({
src: item.data.src,
mode: "widthFix",
onClick: closeOnImg,
style: {
width: '100%'
}
}, Taro.getEnv() !== 'WEB' && {
showMenuByLongpress: showMenuByLongpress
})));
}))), pagination && /*#__PURE__*/ React.createElement(View, {
className: "".concat(classPrefix, "-index")
}, active, "/", maxNo), closeIcon !== false && /*#__PURE__*/ React.createElement(View, {
className: "".concat(classPrefix, "-close ").concat(closeIconPosition),
onClick: onCloseInner
}, closeIcon === true ? /*#__PURE__*/ React.createElement(Close, null) : closeIcon));
};
ImagePreview.displayName = 'NutImagePreview';