MinJieLiu 7 rokov pred
rodič
commit
d1c4562da0
5 zmenil súbory, kde vykonal 145 pridanie a 47 odobranie
  1. 22 0
      src/Photo.tsx
  2. 0 0
      src/PhotoElements.tsx
  3. 59 0
      src/PhotoSlider.tsx
  4. 42 34
      src/PhotoView.tsx
  5. 22 13
      src/Spinner.tsx

+ 22 - 0
src/Photo.tsx

@@ -1,10 +1,12 @@
 import React from 'react';
 import styled from 'styled-components';
+import throttle from 'lodash.throttle';
 import Spinner from './Spinner';
 import { getSuitableImageSize } from './utils';
 
 export interface IPhotoProps extends React.HTMLAttributes<any> {
   src: string;
+  onPhotoResize: () => void;
   loadingElement?: JSX.Element;
   brokenElement?: JSX.Element;
 }
@@ -46,6 +48,16 @@ export default class Photo extends React.Component<IPhotoProps, PhotoState> {
     currPhoto.src = props.src;
     currPhoto.onload = this.handleImageLoaded;
     currPhoto.onerror = this.handleImageBroken;
+
+    this.handleResize = throttle(this.handleResize, 8);
+  }
+
+  componentDidMount() {
+    window.addEventListener('resize', this.handleResize);
+  }
+
+  componentWillUnmount() {
+    window.removeEventListener('resize', this.handleResize);
   }
 
   handleImageLoaded = e => {
@@ -64,6 +76,16 @@ export default class Photo extends React.Component<IPhotoProps, PhotoState> {
     });
   }
 
+  handleResize = () => {
+    const { loaded, naturalWidth, naturalHeight } = this.state;
+    if (loaded) {
+      this.setState(
+        getSuitableImageSize(naturalWidth, naturalHeight),
+        this.props.onPhotoResize,
+      );
+    }
+  }
+
   render() {
     const {
       src,

+ 0 - 0
src/StyledElements.tsx → src/PhotoElements.tsx


+ 59 - 0
src/PhotoSlider.tsx

@@ -0,0 +1,59 @@
+import React from 'react';
+import PhotoView from './PhotoView';
+
+export interface IPhotoSliderProps {
+  // 图片数组
+  imageList: string[];
+  // 图片当前索引
+  index: number;
+  // 索引改变回调
+  onIndexChange: Function;
+}
+
+type PhotoSliderState = {
+};
+
+export default class PhotoSlider extends React.Component<
+  IPhotoSliderProps,
+  PhotoSliderState
+> {
+  static displayName = 'PhotoSlider';
+
+  readonly state = {
+  };
+
+  componentDidMount() {
+  }
+
+  componentWillUnmount() {
+  }
+
+  handleReachTopMove = () => {
+  }
+
+  handleReachLeftMove = () => {
+  }
+
+  handleReachRightMove = () => {
+  }
+
+  render() {
+    const { imageList } = this.props;
+
+    return (
+      <div>
+        {imageList.map((src, index) => (
+          <PhotoView
+            key={index}
+            src={src}
+            onReachTopMove={this.handleReachTopMove}
+            onReachRightMove={index < imageList.length
+              ? this.handleReachRightMove
+              : undefined}
+            onReachLeftMove={index > 0 ? this.handleReachLeftMove : undefined}
+          />
+        ))}
+      </div>
+    );
+  }
+}

+ 42 - 34
src/PhotoView.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 import { Motion, spring } from 'react-motion';
 import throttle from 'lodash.throttle';
 import Photo from './Photo';
-import { PhotoContainer, Backdrop } from './StyledElements';
+import { PhotoContainer, Backdrop } from './PhotoElements';
 import {
   isMobile,
   getMultipleTouchPosition,
@@ -10,58 +10,60 @@ import {
   slideToSuitableOffset,
 } from './utils';
 import { defaultAnimationConfig } from './variables';
-import { animationType } from './types';
 
 export interface IPhotoViewProps {
+  // 图片地址
   src: string;
+  // 容器类名
+  wrapClassName?: string;
+  // 图片类名
+  className?: string;
+
+  // 到达顶部滑动事件
+  onReachTopMove?: Function;
+  // 到达右部滑动事件
+  onReachRightMove?: Function;
+  // 到达底部滑动事件
+  onReachBottomMove?: Function;
+  // 到达左部滑动事件
+  onReachLeftMove?: Function;
 }
 
-type PhotoViewState = {
+const initialState = {
   // 图片 X 偏移量
-  x: number;
+  x: 0,
   // 图片 y 偏移量
-  y: number;
+  y: 0,
   // 图片缩放程度
-  scale: number;
+  scale: 1,
   // 图片处于触摸的状态
-  touched: boolean;
+  touched: false,
+
   // 触摸开始时 x 原始坐标
-  pageX: number;
+  pageX: 0,
   // 触摸开始时 y 原始坐标
-  pageY: number;
+  pageY: 0,
+
   // 触摸开始时图片 x 偏移量
-  lastX: number;
+  lastX: 0,
   // 触摸开始时图片 y 偏移量
-  lastY: number;
-  // 多指触控间距
-  lastTouchLength: number;
+  lastY: 0,
 
   // 触摸开始时时间
-  touchedTime: number;
-} & animationType;
+  touchedTime: 0,
+  // 多指触控间距
+  lastTouchLength: 0,
+  // 动画类型
+  animation: defaultAnimationConfig,
+};
 
 export default class PhotoView extends React.Component<
   IPhotoViewProps,
-  PhotoViewState
+  typeof initialState
 > {
   static displayName = 'PhotoView';
 
-  readonly state = {
-    x: 0,
-    y: 0,
-    scale: 1,
-    touched: false,
-
-    pageX: 0,
-    pageY: 0,
-
-    lastX: 0,
-    lastY: 0,
-
-    touchedTime: 0,
-    lastTouchLength: 0,
-    animation: defaultAnimationConfig,
-  };
+  readonly state = initialState;
 
   private photoRef;
 
@@ -238,12 +240,16 @@ export default class PhotoView extends React.Component<
     this.handleUp(pageX, pageY);
   }
 
+  handleResize = () => {
+    this.setState(initialState);
+  }
+
   handlePhotoRef = (ref) => {
     this.photoRef = ref;
   }
 
   render() {
-    const { src } = this.props;
+    const { src, wrapClassName, className } = this.props;
     const { x, y, scale, touched, animation } = this.state;
     const style = {
       currX: touched ? x : spring(x, animation),
@@ -252,19 +258,21 @@ export default class PhotoView extends React.Component<
     };
 
     return (
-      <PhotoContainer>
+      <PhotoContainer className={wrapClassName}>
         <Backdrop />
         <Motion style={style}>
           {({ currX, currY, currScale }) => {
             const transform = `translate3d(${currX}px, ${currY}px, 0) scale(${currScale})`;
             return (
               <Photo
+                className={className}
                 src={src}
                 ref={this.handlePhotoRef}
                 onDoubleClick={this.handleDoubleClick}
                 onMouseDown={isMobile ? undefined : this.handleMouseDown}
                 onTouchStart={isMobile ? this.handleTouchStart : undefined}
                 onWheel={this.handleWheel}
+                onPhotoResize={this.handleResize}
                 style={{
                   WebkitTransform: transform,
                   transform,

+ 22 - 13
src/Spinner.tsx

@@ -1,28 +1,37 @@
 import React from 'react';
+import styled, { keyframes } from 'styled-components';
 
-export default function Spinner() {
+function Spinner(props: {
+  className?: string;
+}) {
   return (
     <svg
+      className={props.className}
       xmlns="http://www.w3.org/2000/svg"
       viewBox="0 0 32 32"
-      width="64"
-      height="64"
+      width="48"
+      height="48"
       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">
-        <animateTransform
-          attributeName="transform"
-          type="rotate"
-          from="0 16 16"
-          to="360 16 16"
-          dur="0.6s"
-          repeatCount="indefinite"
-        />
-      </path>
+      <path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z" />
     </svg>
   );
 }
+
+const rotate = keyframes`
+  from {
+    transform: rotate(0deg);
+  }
+
+  to {
+    transform: rotate(360deg);
+  }
+`;
+
+export default styled(Spinner)`
+  animation: ${rotate} 0.6s linear infinite;
+`;