UNPKG

@nutui/nutui-react-taro

Version:

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

254 lines (253 loc) 10.8 kB
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';