Browse Source

键盘事件支持

MinJieLiu 5 years ago
parent
commit
db707b733e
5 changed files with 59 additions and 10 deletions
  1. 1 1
      README.md
  2. 1 1
      package.json
  3. 43 0
      src/PhotoSlider.tsx
  4. 12 8
      src/PhotoView.tsx
  5. 2 0
      src/components/VisibleAnimationHandle.tsx

+ 1 - 1
README.md

@@ -9,7 +9,7 @@ Demo: [https://minjieliu.github.io/react-photo-view](https://minjieliu.github.io
 
 ### 特性
 
- 1. 支持基本手势:左右切换、下滑关闭、双击放大/缩小、双指控制、拖动平移、点击切换控件等
+ 1. 支持基本手势:左右切换、下滑关闭、双击放大/缩小、双指控制、拖动平移、键盘控制、点击切换控件等
  1. 打开/关闭缩放动画
  1. 自适应图像适应
  1. 支持桌面端/移动端

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "react-photo-view",
-  "version": "0.3.4",
+  "version": "0.3.5",
   "description": "React photo preview.",
   "author": "MinJieLiu",
   "license": "MIT",

+ 43 - 0
src/PhotoSlider.tsx

@@ -97,6 +97,16 @@ export default class PhotoSlider extends React.Component<
       translateX: index * -(window.innerWidth + horizontalOffset),
       photoIndex: index,
     });
+
+    if (!isMobile) {
+      window.addEventListener('keydown', this.handleKeyDown);
+    }
+  }
+
+  componentWillUnmount() {
+    if (!isMobile) {
+      window.removeEventListener('keydown', this.handleKeyDown);
+    }
   }
 
   handleClose = () => {
@@ -133,6 +143,23 @@ export default class PhotoSlider extends React.Component<
     });
   };
 
+  handleKeyDown = (evt: KeyboardEvent) => {
+    const { visible } = this.props;
+    if (visible) {
+      switch (evt.key) {
+        case 'ArrowLeft':
+          this.handlePrevious();
+          break;
+        case 'ArrowRight':
+          this.handleNext();
+          break;
+        case 'Escape':
+          this.handleClose();
+          break;
+      }
+    }
+  };
+
   handleReachVerticalMove = (clientY, scale) => {
     this.setState(({ lastClientY, backdropOpacity }) => {
       if (lastClientY === undefined) {
@@ -200,6 +227,21 @@ export default class PhotoSlider extends React.Component<
     }
   };
 
+  handlePrevious = () => {
+    const { photoIndex } = this.state;
+    if (photoIndex > 0) {
+      this.handleIndexChange(photoIndex - 1);
+    }
+  };
+
+  handleNext = () => {
+    const { images } = this.props;
+    const { photoIndex } = this.state;
+    if (photoIndex < images.length - 1) {
+      this.handleIndexChange(photoIndex + 1);
+    }
+  };
+
   handleReachMove = (
     reachState: ReachTypeEnum,
     clientX: number,
@@ -371,6 +413,7 @@ export default class PhotoSlider extends React.Component<
                         loadingElement={loadingElement}
                         brokenElement={brokenElement}
                         onPhotoResize={this.handleResize}
+                        isActive={photoIndex === realIndex}
                         showAnimateType={showAnimateType}
                         originRect={originRect}
                         onShowAnimateEnd={onShowAnimateEnd}

+ 12 - 8
src/PhotoView.tsx

@@ -50,6 +50,8 @@ export interface IPhotoViewProps {
   onReachUp: ReachFunction;
   // Resize 事件
   onPhotoResize?: () => void;
+  // 是否在当前操作中
+  isActive: boolean;
 
   // 动画类型
   showAnimateType?: ShowAnimateEnum;
@@ -161,6 +163,10 @@ export default class PhotoView extends React.Component<
 
   onMove = (newClientX: number, newClientY: number, touchLength: number = 0) => {
     const {
+      onReachMove,
+      isActive,
+    } = this.props;
+    const {
       width,
       height,
       naturalWidth,
@@ -176,7 +182,7 @@ export default class PhotoView extends React.Component<
       touched,
       maskTouched,
     } = this.state;
-    if (touched || maskTouched) {
+    if ((touched || maskTouched) && isActive) {
       // 单指最小缩放下,以初始移动距离来判断意图
       if (touchLength === 0 && scale === minScale && this.initialTouchState === TouchStartEnum.Normal) {
         const isBeyondX = Math.abs(newClientX - clientX) > minStartTouchOffset;
@@ -198,9 +204,6 @@ export default class PhotoView extends React.Component<
       // 边缘触发状态
       let currentReachState = ReachTypeEnum.Normal;
       if (touchLength === 0) {
-        const {
-          onReachMove,
-        } = this.props;
         currentX = newClientX - clientX + lastX;
         const planY = newClientY - clientY + lastY;
         const touchYOffset = this.initialTouchState === TouchStartEnum.YPush
@@ -354,6 +357,7 @@ export default class PhotoView extends React.Component<
   handleUp = (newClientX: number, newClientY: number) => {
     // 重置响应状态
     this.initialTouchState = TouchStartEnum.Normal;
+    const { onReachUp, onPhotoTap, onMaskTap, isActive } = this.props;
     const {
       width,
       height,
@@ -369,8 +373,7 @@ export default class PhotoView extends React.Component<
       touched,
       maskTouched,
     } = this.state;
-    if (touched || maskTouched) {
-      const { onReachUp, onPhotoTap, onMaskTap } = this.props;
+    if ((touched || maskTouched) && isActive) {
       const hasMove = clientX !== newClientX || clientY !== newClientY;
       this.setState({
         touched: false,
@@ -430,6 +433,7 @@ export default class PhotoView extends React.Component<
       loadingElement,
       brokenElement,
       onPhotoResize,
+      isActive,
 
       showAnimateType,
       originRect,
@@ -453,8 +457,8 @@ export default class PhotoView extends React.Component<
       <div className={classNames('PhotoView__PhotoWrap', viewClassName)} style={style}>
         <div
           className="PhotoView__PhotoMask"
-          onMouseDown={isMobile ? undefined : this.handleMaskMouseDown}
-          onTouchStart={isMobile ? this.handleMaskTouchStart : undefined}
+          onMouseDown={!isMobile && isActive ? this.handleMaskMouseDown: undefined}
+          onTouchStart={isMobile && isActive ? this.handleMaskTouchStart : undefined}
         />
         <div
           className={classNames({

+ 2 - 0
src/components/VisibleAnimationHandle.tsx

@@ -49,6 +49,8 @@ export default function VisibleAnimationHandle({
         clientX: left + width / 2,
         clientY: top + height / 2,
       });
+    } else if (originRect && !originRef) {
+      updateOriginRect(undefined);
     }
 
     if (visible) {