@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
182 lines (181 loc) • 7.15 kB
JavaScript
import React__default, { useRef, useState, useEffect } from "react";
import classNames from "classnames";
import { Close } from "@nutui/icons-react";
import Popup__default from "./Popup.js";
import Image__default from "./Image.js";
import Video__default from "./Video.js";
import Swiper__default from "./Swiper.js";
import SwiperItem__default from "./SwiperItem.js";
import { C as ComponentDefaults } from "./typings.js";
import { u as usePropsValue } from "./use-props-value.js";
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { images: [], videos: [], visible: false, autoPlay: 3e3, defaultValue: 0, closeOnContentClick: false, pagination: true, indicator: false, indicatorColor: "#fff", closeIcon: false, closeIconPosition: "top-right", onChange: (value) => {
}, onClose: () => {
} });
const ImagePreview = (props) => {
const { value, className, style, images, videos, visible, defaultValue, indicatorColor, pagination, indicator, autoPlay, closeOnContentClick, closeIcon, closeIconPosition, onClose, onChange } = Object.assign(Object.assign({}, defaultProps), props);
const classPrefix = "nut-imagepreview";
const ref = useRef(null);
const [innerNo, setInnerNo] = usePropsValue({
value,
defaultValue,
finalValue: defaultValue,
onChange: (val) => {
onChange === null || onChange === void 0 ? void 0 : onChange(val);
}
});
const [showPop, setShowPop] = useState(visible);
const [active, setActive] = useState(0);
const [maxNo, setMaxNo] = useState((images === null || images === void 0 ? void 0 : images.length) || 0 + ((videos === null || videos === void 0 ? void 0 : videos.length) || 0));
const [store, setStore] = useState({
scale: 1,
moveable: false
});
const [lastTouchEndTime, setLastTouchEndTime] = useState(0);
const onTouchStart = (event) => {
const touches = event.touches;
const events = touches[0];
const events2 = touches[1];
const curTouchTime = (/* @__PURE__ */ new Date()).getTime();
if (curTouchTime - lastTouchEndTime < 300) {
const store12 = store;
if (store12.scale > 1) {
store12.scale = 1;
} else if (store12.scale === 1) {
store12.scale = 2;
}
scaleNow();
}
const store1 = store;
store1.moveable = true;
if (events2) {
store1.oriDistance = getDistance({
x: events.pageX,
y: events.pageY
}, {
x: events2.pageX,
y: events2.pageY
});
}
store1.originScale = store1.scale || 1;
};
const onTouchMove = (event) => {
const touches = event.touches;
const events = touches[0];
const events2 = touches[1];
if (!store.moveable) {
return;
}
const store1 = store;
if (events2) {
const curDistance = getDistance({
x: events.pageX,
y: events.pageY
}, {
x: events2.pageX,
y: events2.pageY
});
const curScale = curDistance / store1.oriDistance;
store1.scale = store1.originScale * curScale;
if (store1.scale > 3) {
store1.scale = 3;
}
scaleNow();
}
};
const onTouchEnd = () => {
setLastTouchEndTime((/* @__PURE__ */ new Date()).getTime());
const store1 = store;
store1.moveable = false;
if (store1.scale < 1.1 && store1.scale > 1 || store1.scale < 1) {
store1.scale = 1;
scaleNow();
}
};
useEffect(() => {
init();
}, []);
const init = () => {
document.addEventListener("touchmove", onTouchMove);
document.addEventListener("touchend", onTouchEnd);
document.addEventListener("touchcancel", onTouchEnd);
};
useEffect(() => {
setShowPop(visible);
}, [visible]);
useEffect(() => {
setInnerNo(defaultValue || 1);
}, [defaultValue]);
useEffect(() => {
setActive(innerNo);
}, [innerNo]);
useEffect(() => {
setMaxNo((images === null || images === void 0 ? void 0 : images.length) || 0 + ((videos === null || videos === void 0 ? void 0 : videos.length) || 0));
}, [images, videos]);
const scaleNow = () => {
if (ref.current) {
ref.current.style.transform = `scale(${store.scale})`;
}
};
const getDistance = (first, second) => {
return Math.hypot(Math.abs(second.x - first.x), Math.abs(second.y - first.y));
};
const slideChangeEnd = (page) => {
setActive(page + 1);
onChange === null || onChange === void 0 ? void 0 : onChange(page + 1);
};
const onCloseInner = (e) => {
e.stopPropagation();
setShowPop(false);
setActive(innerNo);
scaleNow();
onClose && onClose();
setStore(Object.assign(Object.assign({}, store), { scale: 1 }));
};
const closeOnImg = (e) => {
e.stopPropagation();
if (closeOnContentClick) {
onCloseInner(e);
}
};
const duration = typeof autoPlay === "string" ? parseInt(autoPlay) : autoPlay;
return React__default.createElement(
Popup__default,
{ visible: showPop, className: `${classPrefix}-pop`, style: { width: "100%" }, onClick: onCloseInner },
React__default.createElement("div", { className: classNames(classPrefix, className), style, ref, onTouchStart }, showPop ? React__default.createElement(Swiper__default, { autoPlay: !!duration, duration, className: `${classPrefix}-swiper`, loop: true, style: {
"--nutui-indicator-color": indicatorColor
}, direction: "horizontal", onChange: (page) => slideChangeEnd(page), defaultValue: innerNo && (innerNo > maxNo ? maxNo - 1 : innerNo - 1), indicator }, (videos !== null && videos !== void 0 ? videos : []).map((item) => ({ type: "video", data: item })).concat((images !== null && images !== void 0 ? images : []).map((item) => ({ type: "image", data: item }))).sort((a, b) => {
var _a, _b, _c, _d;
return ((_b = (_a = a.data) === null || _a === void 0 ? void 0 : _a.index) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = b.data) === null || _c === void 0 ? void 0 : _c.index) !== null && _d !== void 0 ? _d : 0);
}).map((item, index) => {
if (item.type === "video") {
const { source, options } = item.data;
return React__default.createElement(
SwiperItem__default,
{ key: index },
React__default.createElement(Video__default, { source, options, onClick: closeOnImg })
);
}
if (item.type === "image") {
const { src } = item.data;
return React__default.createElement(
SwiperItem__default,
{ key: index },
React__default.createElement(Image__default, { src, draggable: false, onClick: closeOnImg })
);
}
return null;
})) : null),
pagination ? React__default.createElement(
"div",
{ className: `${classPrefix}-index` },
active,
"/",
(images ? images.length : 0) + (videos ? videos.length : 0)
) : null,
closeIcon !== false ? React__default.createElement("div", { className: `${classPrefix}-close ${closeIconPosition}`, onClick: onCloseInner }, closeIcon === true ? React__default.createElement(Close, null) : closeIcon) : null
);
};
ImagePreview.displayName = "NutImagePreview";
export {
ImagePreview as default
};