MinJieLiu 7 роки тому
батько
коміт
1c7e1205fb

+ 20 - 4
src/PhotoSlider.tsx

@@ -33,6 +33,8 @@ type PhotoSliderState = {
   lastPageY: number | undefined;
   // 背景透明度
   backdropOpacity: number;
+  // 缩放度
+  photoScale: number;
 };
 
 export default class PhotoSlider extends React.Component<
@@ -66,6 +68,7 @@ export default class PhotoSlider extends React.Component<
       lastPageX: undefined,
       lastPageY: undefined,
       backdropOpacity: defaultOpacity,
+      photoScale: 1,
     };
   }
 
@@ -95,6 +98,7 @@ export default class PhotoSlider extends React.Component<
           touched: true,
           lastPageY: pageY,
           backdropOpacity,
+          photoScale: 1,
         };
       }
       const offsetPageY = pageY - lastPageY;
@@ -102,9 +106,13 @@ export default class PhotoSlider extends React.Component<
         touched: true,
         lastPageY,
         backdropOpacity: Math.max(
-          Math.min(defaultOpacity, defaultOpacity - (offsetPageY / 100)),
+          Math.min(defaultOpacity, defaultOpacity - (offsetPageY / 100 / 2)),
           defaultOpacity / 6,
         ),
+        photoScale: Math.max(
+          Math.min(1, 1 - (offsetPageY / 100 / 10)),
+          0.6,
+        ),
       };
     });
   }
@@ -165,19 +173,26 @@ export default class PhotoSlider extends React.Component<
       lastPageX: undefined,
       lastPageY: undefined,
       backdropOpacity: defaultOpacity,
+      photoScale: 1,
     });
   }
 
   render() {
-    const { images, visible, overlay } = this.props;
-    const { translateX, touched, backdropOpacity } = this.state;
     const { innerWidth } = window;
+    const { images, visible, overlay } = this.props;
+    const {
+      translateX,
+      touched,
+      photoIndex,
+      backdropOpacity,
+      photoScale,
+    } = this.state;
     const transform = `translate3d(-${translateX}px, 0px, 0)`;
 
     if (visible) {
       return (
         <SlideWrap>
-          <Backdrop style={{ opacity: backdropOpacity }} />
+          <Backdrop style={{ background: `rgba(0, 0, 0, ${backdropOpacity})` }} />
           {images.map((src, index) => {
             return (
               <PhotoView
@@ -189,6 +204,7 @@ export default class PhotoSlider extends React.Component<
                   : undefined}
                 onReachLeftMove={index > 0 ? this.handleReachHorizontalMove : undefined}
                 onReachUp={this.handleReachUp}
+                photoScale={photoIndex === index ? photoScale : 1}
                 style={{
                   left: `${innerWidth * index}px`,
                   WebkitTransform: transform,

+ 75 - 25
src/PhotoView.tsx

@@ -27,6 +27,8 @@ export interface IPhotoViewProps {
   className?: string;
   // style
   style?: object;
+  // 缩放,用于下拉关闭变小的效果
+  photoScale?: number;
 
   // 到达顶部滑动事件
   onReachTopMove?: ReachFunction;
@@ -68,6 +70,9 @@ const initialState = {
   lastTouchLength: 0,
   // 动画类型
   animation: defaultAnimationConfig,
+
+  // 当前边缘触发状态,0: 未触发,1: x 轴,2: y 轴
+  reachState: 0,
 };
 
 export default class PhotoView extends React.Component<
@@ -120,7 +125,7 @@ export default class PhotoView extends React.Component<
   handleMove = (newPageX: number, newPageY: number, touchLength: number = 0) => {
     if (this.state.touched) {
       const { width, naturalWidth } = this.photoRef.state;
-      this.setState(({
+      const {
         x,
         y,
         pageX,
@@ -129,17 +134,32 @@ export default class PhotoView extends React.Component<
         lastY,
         scale,
         lastTouchLength,
-      }) => {
-        let currentX = x;
-        let currentY = y;
-        if (touchLength === 0) {
-          currentX = newPageX - pageX + lastX;
-          currentY = newPageY - pageY + lastY;
-          const isStopMove = this.handleReachCallback(currentX, currentY, scale, newPageX, newPageY);
-          if (isStopMove) {
-            return null;
-          }
-        }
+        reachState,
+      } = this.state;
+      let currentX = x;
+      let currentY = y;
+      // 边缘状态
+      let currentReachState = 0;
+      if (touchLength === 0) {
+        currentX = newPageX - pageX + lastX;
+        currentY = newPageY - pageY + lastY;
+        // 边缘触发检测
+        currentReachState = this.handleReachCallback(
+          currentX,
+          currentY,
+          scale,
+          newPageX,
+          newPageY,
+          reachState,
+        );
+      }
+      // 横向边缘触发禁用当前滑动
+      if (currentReachState === 1) {
+        this.setState({
+          reachState: 1,
+        });
+      } else {
+        // 目标倍数
         const endScale = scale + (touchLength - lastTouchLength) / 100 / 2 * scale;
         // 限制最大倍数和最小倍数
         const toScale = Math.max(
@@ -149,8 +169,9 @@ export default class PhotoView extends React.Component<
           ),
           minScale - scaleBuffer,
         );
-        return {
+        this.setState({
           lastTouchLength: touchLength,
+          reachState: currentReachState,
           ...getPositionOnMoveOrScale({
             x: currentX,
             y: currentY,
@@ -159,8 +180,8 @@ export default class PhotoView extends React.Component<
             fromScale: scale,
             toScale,
           }),
-        };
-      });
+        });
+      }
     }
   }
 
@@ -186,6 +207,7 @@ export default class PhotoView extends React.Component<
   }
 
   handleWheel = (e) => {
+    e.preventDefault();
     const { pageX, pageY, deltaY } = e;
     const { width, naturalWidth } = this.photoRef.state;
     this.setState(({ x, y, scale }) => {
@@ -274,6 +296,7 @@ export default class PhotoView extends React.Component<
         return {
           touched: false,
           scale: toScale,
+          reachState: 0, // 重置触发状态
           ...slideToSuitableOffset({
             x,
             y,
@@ -314,7 +337,8 @@ export default class PhotoView extends React.Component<
     scale: number,
     newPageX: number,
     newPageY: number,
-  ): boolean => {
+    reachState: number,
+  ): number => {
     const { width, height } = this.photoRef.state;
 
     const horizontalType = getClosedHorizontal(x, scale, width);
@@ -326,18 +350,44 @@ export default class PhotoView extends React.Component<
       onReachLeftMove,
     } = this.props;
     //  触碰到边缘
-    if (horizontalType && onReachLeftMove && x > minReachOffset) {
+    if (
+      onReachLeftMove
+      && (horizontalType
+      && x > minReachOffset
+      && reachState === 0
+      || reachState === 1)
+    ) {
       onReachLeftMove(newPageX, newPageY);
-      return true;
-    } else if (horizontalType && onReachRightMove && x < -minReachOffset) {
+      return 1;
+    } else if (
+      onReachRightMove
+      && (horizontalType
+      && x < -minReachOffset
+      && reachState === 0
+      || reachState === 1)
+    ) {
       onReachRightMove(newPageX, newPageY);
-      return true;
-    } else if (verticalType && onReachTopMove && y > minReachOffset) {
+      return 1;
+    } else if (
+      onReachTopMove
+      && (verticalType
+      && y > minReachOffset
+      && reachState === 0
+      || reachState === 2)
+    ) {
       onReachTopMove(newPageX, newPageY);
-    } else if (verticalType && onReachBottomMove && y < -minReachOffset) {
+      return 2;
+    } else if (
+      onReachBottomMove
+      && (verticalType
+      && y < -minReachOffset
+      && reachState === 0
+      || reachState === 2)
+    ) {
       onReachBottomMove(newPageX, newPageY);
+      return 2;
     }
-    return false;
+    return 0;
   }
 
   handlePhotoRef = (ref) => {
@@ -345,7 +395,7 @@ export default class PhotoView extends React.Component<
   }
 
   render() {
-    const { src, wrapClassName, className, style } = this.props;
+    const { src, wrapClassName, className, style, photoScale = 1 } = this.props;
     const { x, y, scale, touched, animation } = this.state;
 
     return (
@@ -358,7 +408,7 @@ export default class PhotoView extends React.Component<
           }}
         >
           {({ currX, currY, currScale }) => {
-            const transform = `translate3d(${currX}px, ${currY}px, 0) scale(${currScale})`;
+            const transform = `translate3d(${currX}px, ${currY}px, 0) scale(${currScale * photoScale})`;
             return (
               <Photo
                 className={className}

+ 1 - 1
src/components/Backdrop.tsx

@@ -6,7 +6,7 @@ const Backdrop = styled.div`
   left: 0;
   width: 100%;
   height: 100%;
-  background: black;
+  background: rgba(0, 0, 0, 0.6);
   z-index: -1;
 `;
 

+ 2 - 2
src/components/SlideWrap.tsx

@@ -17,8 +17,8 @@ export default class SlideWrap extends React.Component<{
 }> {
   static displayName = 'SlideWrap';
 
-  dialogNode;
-  originalOverflow;
+  private dialogNode;
+  private originalOverflow;
 
   constructor(props) {
     super(props);

+ 2 - 2
src/components/Spinner.tsx

@@ -9,8 +9,8 @@ function Spinner(props: {
       className={props.className}
       xmlns="http://www.w3.org/2000/svg"
       viewBox="0 0 32 32"
-      width="48"
-      height="48"
+      width="36"
+      height="36"
       fill="white"
     >
       <path

+ 2 - 2
src/variables.ts

@@ -13,12 +13,12 @@ export const maxMoveOffset: number = 40;
 /**
  * 最小触发边缘事件距离
  */
-export const minReachOffset: number = 40;
+export const minReachOffset: number = 20;
 
 /**
  * 下拉关闭页面触发距离
  */
-export const closePageOffset: number = 60;
+export const closePageOffset: number = 80;
 
 /**
  * 默认背景透明度