Explorar el Código

解决背景点击穿透的问题

MinJieLiu hace 7 años
padre
commit
43121257d6
Se han modificado 5 ficheros con 70 adiciones y 43 borrados
  1. 1 1
      package.json
  2. 19 12
      src/PhotoSlider.tsx
  3. 36 22
      src/PhotoView.tsx
  4. 2 8
      src/types.ts
  5. 12 0
      src/utils/getCurrentFromEvent.ts

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "react-photo-view",
-  "version": "0.1.8",
+  "version": "0.1.9",
   "description": "React photo preview.",
   "main": "./lib/index",
   "module": "./es/index",

+ 19 - 12
src/PhotoSlider.tsx

@@ -3,7 +3,7 @@ import PhotoView from './PhotoView';
 import SlideWrap from './components/SlideWrap';
 import Backdrop from './components/Backdrop';
 import { Close, Counter, TopBar } from './components/TopWrap';
-import { dataType, TouchTypeEnum } from './types';
+import { dataType } from './types';
 import { defaultOpacity, horizontalOffset, maxMoveOffset } from './variables';
 
 interface IPhotoSliderProps {
@@ -61,6 +61,10 @@ export default class PhotoSlider extends React.Component<
 > {
   static displayName = 'PhotoSlider';
 
+  static defaultProps = {
+    maskClosable: true,
+  };
+
   static getDerivedStateFromProps(nextProps, prevState) {
     if (
       nextProps.index !== undefined &&
@@ -109,6 +113,16 @@ export default class PhotoSlider extends React.Component<
     }));
   }
 
+  handlePhotoMaskClick = () => {
+    const { maskClosable, onClose } = this.props;
+    if (maskClosable) {
+      onClose();
+      this.setState({
+        overlayVisible: true,
+      });
+    }
+  }
+
   handleResize = () => {
     const { innerWidth } = window;
     this.setState(({ photoIndex }) => {
@@ -162,9 +176,9 @@ export default class PhotoSlider extends React.Component<
     });
   }
 
-  handleReachUp = (clientX: number, clientY: number, touchType: TouchTypeEnum) => {
+  handleReachUp = (clientX: number, clientY: number) => {
     const { innerWidth, innerHeight } = window;
-    const { images, onIndexChange, onClose, maskClosable = true } = this.props;
+    const { images, onIndexChange, onClose } = this.props;
     const {
       lastClientX = clientX,
       lastClientY = clientY,
@@ -181,15 +195,7 @@ export default class PhotoSlider extends React.Component<
     let currentPhotoIndex = photoIndex;
     let isChangeVisible = false;
 
-    // mask 点击事件
-    if (lastClientX === clientX
-      && lastClientY === clientY
-      && maskClosable
-      && touchType === TouchTypeEnum.Mask
-    ) {
-      isChangeVisible = true;
-      onClose();
-    } else if (Math.abs(offsetClientY) > innerHeight * 0.14) {
+    if (Math.abs(offsetClientY) > innerHeight * 0.14) {
       isChangeVisible = true;
       onClose();
       // 下一张
@@ -287,6 +293,7 @@ export default class PhotoSlider extends React.Component<
                   }
                   onReachUp={this.handleReachUp}
                   onPhotoClick={this.handlePhotoClick}
+                  onMaskClick={this.handlePhotoMaskClick}
                   photoScale={photoIndex === realIndex ? photoScale : 1}
                   wrapClassName={viewClassName}
                   className={imageClassName}

+ 36 - 22
src/PhotoView.tsx

@@ -5,12 +5,17 @@ import PhotoWrap from './components/PhotoWrap';
 import PhotoMask from './components/PhotoMask';
 import throttle from './utils/throttle';
 import isMobile from './utils/isMobile';
+import getCurrentFromEvent from './utils/getCurrentFromEvent';
 import getMultipleTouchPosition from './utils/getMultipleTouchPosition';
 import getPositionOnMoveOrScale from './utils/getPositionOnMoveOrScale';
 import slideToSuitableOffset from './utils/slideToSuitableOffset';
 import { getClosedHorizontal, getClosedVertical } from './utils/getCloseEdge';
 import { maxScale, minReachOffset, minScale, scaleBuffer } from './variables';
-import { ReachFunction, ReachTypeEnum, TouchTypeEnum } from './types';
+import {
+  ReachFunction,
+  PhotoClickFunction,
+  ReachTypeEnum,
+} from './types';
 
 interface IPhotoViewProps {
   // 图片地址
@@ -29,7 +34,9 @@ interface IPhotoViewProps {
   brokenElement?: JSX.Element;
 
   // Photo 点击事件
-  onPhotoClick?: (clientX: number, clientY: number) => void;
+  onPhotoClick?: PhotoClickFunction;
+  // Mask 点击事件
+  onMaskClick?: PhotoClickFunction;
   // 到达顶部滑动事件
   onReachTopMove?: ReachFunction;
   // 到达右部滑动事件
@@ -39,7 +46,7 @@ interface IPhotoViewProps {
   // 到达左部滑动事件
   onReachLeftMove?: ReachFunction;
   // 触摸解除事件
-  onReachUp?: (clientX: number, clientY: number, TouchTypeEnum) => void;
+  onReachUp?: (clientX: number, clientY: number) => void;
 
   onPhotoResize?: () => void;
 }
@@ -84,11 +91,10 @@ export default class PhotoView extends React.Component<
   readonly state = initialState;
 
   private photoRef;
-  private readonly onPhotoClick;
 
   constructor(props) {
     super(props);
-    this.onPhotoClick = debounce(this.debouncePhotoClick, 400);
+    this.photoClick = debounce(this.photoClick, 300);
     this.handleMove = throttle(this.handleMove, 8);
   }
 
@@ -188,22 +194,26 @@ export default class PhotoView extends React.Component<
     }
   }
 
-  debouncePhotoClick = (newClientX: number, newClientY: number) => {
+  photoClick = (newClientX: number, newClientY: number) => {
     const { onPhotoClick } = this.props;
     const { clientX, clientY } = this.state;
-    if (onPhotoClick && clientX === newClientX && clientY === newClientY) {
+    if (onPhotoClick
+      && Math.abs(clientX - newClientX) < 5
+      && Math.abs(clientY - newClientY) < 5
+    ) {
       onPhotoClick(newClientX, newClientY);
     }
   }
 
   handlePhotoClick = (e) => {
-    this.onPhotoClick(e.clientX, e.clientY);
+    const { clientX, clientY } = getCurrentFromEvent(e);
+    this.photoClick(clientX, clientY);
   }
 
   handleDoubleClick = (e) => {
     e.preventDefault();
-    // 取消 click 事件
-    this.onPhotoClick.cancel();
+    // @ts-ignore 取消 click 事件
+    this.photoClick.cancel();
     const { clientX, clientY } = e;
     const { width, naturalWidth } = this.photoRef.state;
     this.setState(({ x, y, scale }) => {
@@ -259,7 +269,6 @@ export default class PhotoView extends React.Component<
       clientY,
       lastX: prevState.x,
       lastY: prevState.y,
-      touchedTime: Date.now(),
     }));
   }
 
@@ -272,6 +281,19 @@ export default class PhotoView extends React.Component<
     this.handleMaskStart(clientX, clientY);
   }
 
+  handleMaskClick = (e) => {
+    const evt = getCurrentFromEvent(e);
+    const { onMaskClick } = this.props;
+    const { clientX, clientY } = this.state;
+    if (
+      onMaskClick
+      && Math.abs(clientX - evt.clientX) < 5
+      && Math.abs(clientY - evt.clientY) < 5
+    ) {
+      onMaskClick(clientX, clientY);
+    }
+  }
+
   handleTouchStart = e => {
     if (e.touches.length >= 2) {
       const { clientX, clientY, touchLength } = getMultipleTouchPosition(e);
@@ -319,21 +341,12 @@ export default class PhotoView extends React.Component<
         clientY,
       }) => {
         if (onReachUp) {
-          onReachUp(
-            newClientX,
-            newClientY,
-            maskTouched
-              ? TouchTypeEnum.Mask
-              : TouchTypeEnum.Image,
-          );
+          onReachUp(newClientX, newClientY);
         }
         const hasMove = clientX !== newClientX || clientY !== newClientY;
         // 缩放弹性效果
         const toScale = Math.max(
-          Math.min(
-            scale,
-            Math.max(maxScale, naturalWidth / width),
-          ),
+          Math.min(scale, Math.max(maxScale, naturalWidth / width)),
           minScale,
         );
         return {
@@ -460,6 +473,7 @@ export default class PhotoView extends React.Component<
         <PhotoMask
           onMouseDown={isMobile ? undefined : this.handleMaskMouseDown}
           onTouchStart={isMobile ? this.handleMaskTouchStart : undefined}
+          onClick={this.handleMaskClick}
         />
         <Photo
           className={className}

+ 2 - 8
src/types.ts

@@ -8,6 +8,8 @@ export type dataType = {
 
 export type ReachFunction = (clientX: number, clientY: number) => void;
 
+export type PhotoClickFunction = (clientX: number, clientY: number) => void;
+
 /**
  * 边缘超出状态
  */
@@ -26,11 +28,3 @@ export enum ReachTypeEnum {
   XReach, // x 轴
   YReach, // y 轴
 }
-
-/**
- * 触摸类型
- */
-export enum TouchTypeEnum {
-  Image = 1, // 图片
-  Mask, // 背景
-}

+ 12 - 0
src/utils/getCurrentFromEvent.ts

@@ -0,0 +1,12 @@
+/**
+ * 获取 mouse 或 touch 事件的当前节点
+ * @param evt
+ */
+const getCurrentFromEvent = (evt) => {
+  if (evt.touches && evt.touches.length) {
+    return evt.touches[0];
+  }
+  return evt;
+};
+
+export default getCurrentFromEvent;