UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

182 lines (181 loc) 7.15 kB
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 };