Ver código fonte

fix: 滑动关闭背景闪烁的问题, feat: Spinner 延迟出现,避免闪烁

MinJieLiu 5 anos atrás
pai
commit
f629d9fa16
5 arquivos alterados com 64 adições e 35 exclusões
  1. 1 1
      package.json
  2. 32 18
      src/PhotoSlider.tsx
  3. 0 1
      src/PhotoView.less
  4. 16 1
      src/components/Spinner.less
  5. 15 14
      src/components/Spinner.tsx

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "react-photo-view",
-  "version": "0.3.7",
+  "version": "0.3.8",
   "description": "一款精致的 React 的图片预览组件",
   "author": "MinJieLiu",
   "license": "MIT",

+ 32 - 18
src/PhotoSlider.tsx

@@ -44,6 +44,8 @@ type PhotoSliderState = {
   lastClientY: number | undefined;
   // 背景透明度
   backdropOpacity: number;
+  // 上次关闭的背景透明度
+  lastBackdropOpacity: number;
   // 覆盖物可见度
   overlayVisible: boolean;
   // 可下拉关闭
@@ -88,6 +90,7 @@ export default class PhotoSlider extends React.Component<
       lastClientX: undefined,
       lastClientY: undefined,
       backdropOpacity: defaultOpacity,
+      lastBackdropOpacity: defaultOpacity,
       overlayVisible: true,
       canPullClose: true,
     };
@@ -113,14 +116,19 @@ export default class PhotoSlider extends React.Component<
   }
 
   handleClose = () => {
-    this.props.onClose();
+    const { onClose } = this.props;
+    const { backdropOpacity } = this.state;
+    onClose();
     this.setState({
       overlayVisible: true,
+      // 记录当前关闭时的透明度
+      lastBackdropOpacity: backdropOpacity,
     });
   };
 
   handlePhotoTap = () => {
-    if (this.props.photoClosable) {
+    const { photoClosable } = this.props;
+    if (photoClosable) {
       this.handleClose();
     } else {
       this.setState(prevState => ({
@@ -130,7 +138,8 @@ export default class PhotoSlider extends React.Component<
   };
 
   handlePhotoMaskTap = () => {
-    if (this.props.maskClosable) {
+    const { maskClosable } = this.props;
+    if (maskClosable) {
       this.handleClose();
     }
   };
@@ -268,7 +277,7 @@ export default class PhotoSlider extends React.Component<
   };
 
   handleReachUp = (clientX: number, clientY: number) => {
-    const { images, onClose } = this.props;
+    const { images } = this.props;
     const {
       lastClientX = clientX,
       lastClientY = clientY,
@@ -279,7 +288,7 @@ export default class PhotoSlider extends React.Component<
 
     const offsetClientX = clientX - lastClientX;
     const offsetClientY = clientY - lastClientY;
-    let isChangeVisible = false;
+    let willClose = false;
     // 下一张
     if (offsetClientX < -maxMoveOffset && photoIndex < images.length - 1) {
       this.handleIndexChange(photoIndex + 1);
@@ -297,8 +306,8 @@ export default class PhotoSlider extends React.Component<
     let currentPhotoIndex = photoIndex;
 
     if (Math.abs(offsetClientY) > window.innerHeight * 0.14 && canPullClose) {
-      isChangeVisible = true;
-      onClose();
+      willClose = true;
+      this.handleClose();
     }
     this.setState({
       touched: false,
@@ -307,7 +316,7 @@ export default class PhotoSlider extends React.Component<
       lastClientX: undefined,
       lastClientY: undefined,
       backdropOpacity: defaultOpacity,
-      overlayVisible: isChangeVisible ? true : overlayVisible,
+      overlayVisible: willClose ? true : overlayVisible,
     });
   };
 
@@ -319,7 +328,6 @@ export default class PhotoSlider extends React.Component<
       maskClassName,
       viewClassName,
       imageClassName,
-      onClose,
       bannerVisible,
       introVisible,
       overlayRender,
@@ -331,6 +339,7 @@ export default class PhotoSlider extends React.Component<
       touched,
       photoIndex,
       backdropOpacity,
+      lastBackdropOpacity,
       overlayVisible,
       shouldTransition,
     } = this.state;
@@ -345,12 +354,15 @@ export default class PhotoSlider extends React.Component<
         {({ photoVisible, showAnimateType, originRect, onShowAnimateEnd }) => {
           if (photoVisible) {
             const { innerWidth } = window;
+            const currentOverlayVisible =
+              overlayVisible && showAnimateType === ShowAnimateEnum.None;
             const overlayStyle = {
-              opacity:
-                overlayVisible && showAnimateType === ShowAnimateEnum.None
-                  ? 1
-                  : 0,
+              opacity: +currentOverlayVisible,
             };
+            // 关闭过程中使用下拉保存的透明度
+            const currentOpacity = visible
+              ? backdropOpacity
+              : lastBackdropOpacity;
 
             return (
               <SlideWrap className={className}>
@@ -365,7 +377,9 @@ export default class PhotoSlider extends React.Component<
                         showAnimateType === ShowAnimateEnum.Out,
                     },
                   )}
-                  style={{ background: `rgba(0, 0, 0, ${backdropOpacity})` }}
+                  style={{
+                    background: `rgba(0, 0, 0, ${currentOpacity})`,
+                  }}
                   onAnimationEnd={onShowAnimateEnd}
                 />
                 {bannerVisible && (
@@ -379,8 +393,8 @@ export default class PhotoSlider extends React.Component<
                     <div className="PhotoView-PhotoSlider__BannerRight">
                       <CloseSVG
                         className="PhotoView-PhotoSlider__Close"
-                        onTouchEnd={isMobile ? onClose : undefined}
-                        onClick={isMobile ? undefined : onClose}
+                        onTouchEnd={isMobile ? this.handleClose : undefined}
+                        onClick={isMobile ? undefined : this.handleClose}
                       />
                     </div>
                   </div>
@@ -441,9 +455,9 @@ export default class PhotoSlider extends React.Component<
                     images,
                     index: photoIndex,
                     visible,
-                    onClose,
+                    onClose: this.handleClose,
                     onIndexChange: this.handleIndexChange,
-                    overlayVisible,
+                    overlayVisible: currentOverlayVisible,
                   })}
               </SlideWrap>
             );

+ 0 - 1
src/PhotoView.less

@@ -21,7 +21,6 @@
 }
 
 .PhotoView {
-
   &__animateIn {
     opacity: 0.4;
     animation: PhotoView__animateIn 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) both;

+ 16 - 1
src/components/Spinner.less

@@ -8,8 +8,23 @@
   }
 }
 
+@keyframes PhotoView__delayShow {
+  0%,
+  50% {
+    opacity: 0;
+  }
+
+  100% {
+    opacity: 1;
+  }
+}
+
 .PhotoView {
   &__Spinner {
-    animation: PhotoView__rotate 0.6s linear infinite;
+    animation: PhotoView__delayShow 0.4s linear both;
+
+    svg {
+      animation: PhotoView__rotate 0.6s linear infinite;
+    }
   }
 }

+ 15 - 14
src/components/Spinner.tsx

@@ -3,20 +3,21 @@ import './Spinner.less';
 
 function Spinner() {
   return (
-    <svg
-      className="PhotoView__Spinner"
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 32 32"
-      width="36"
-      height="36"
-      fill="white"
-    >
-      <path
-        opacity=".25"
-        d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"
-      />
-      <path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z" />
-    </svg>
+    <div className="PhotoView__Spinner">
+      <svg
+        xmlns="http://www.w3.org/2000/svg"
+        viewBox="0 0 32 32"
+        width="36"
+        height="36"
+        fill="white"
+      >
+        <path
+          opacity=".25"
+          d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"
+        />
+        <path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z" />
+      </svg>
+    </div>
   );
 }