From 0675d2a4f76496c229ec9dab2ba8656b97b32c18 Mon Sep 17 00:00:00 2001 From: MinJieLiu Date: Thu, 17 Mar 2022 15:55:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20`loadingElement`=20=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20fix:=20=E5=9B=BE=E7=89=87=E6=94=BE?= =?UTF-8?q?=E5=A4=A7=E9=99=90=E5=88=B6=E4=BC=98=E5=8C=96=20fix:=20?= =?UTF-8?q?=E4=B8=AA=E5=88=AB=E6=9C=BA=E5=9E=8B=E4=B8=AD=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E9=A2=84=E8=A7=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/example/components/doc-broken.tsx | 13 ++- .../example/icons/EosIconsBubbleLoading.tsx | 97 +++++++++++++++++++ .../example/pages/docs/change-log.en-US.mdx | 6 ++ .../example/pages/docs/change-log.zh-CN.mdx | 6 ++ .../pages/docs/getting-started.en-US.mdx | 4 +- .../pages/docs/getting-started.zh-CN.mdx | 4 +- packages/react-photo-view/package.json | 2 +- packages/react-photo-view/src/Photo.tsx | 9 +- packages/react-photo-view/src/PhotoBox.tsx | 62 +++++------- packages/react-photo-view/src/PhotoSlider.tsx | 6 +- packages/react-photo-view/src/PhotoView.tsx | 35 +------ .../src/hooks/useScrollPosition.ts | 17 ++-- .../src/utils/isTouchDevice.ts | 2 +- 13 files changed, 157 insertions(+), 106 deletions(-) create mode 100644 packages/example/icons/EosIconsBubbleLoading.tsx diff --git a/packages/example/components/doc-broken.tsx b/packages/example/components/doc-broken.tsx index 034b709..ad65a56 100644 --- a/packages/example/components/doc-broken.tsx +++ b/packages/example/components/doc-broken.tsx @@ -1,19 +1,18 @@ import React from 'react'; import { PhotoProvider, PhotoView } from 'react-photo-view'; import { Button, ImageList } from './doc-components'; +import { EosIconsBubbleLoading } from '../icons/EosIconsBubbleLoading'; import defaultPhoto from '../images/default-photo.svg'; export default function DocDemo() { return ( - + } + brokenElement={} + > - - - - }> - - + diff --git a/packages/example/icons/EosIconsBubbleLoading.tsx b/packages/example/icons/EosIconsBubbleLoading.tsx new file mode 100644 index 0000000..88563bb --- /dev/null +++ b/packages/example/icons/EosIconsBubbleLoading.tsx @@ -0,0 +1,97 @@ +import React, { SVGProps } from 'react'; + +export function EosIconsBubbleLoading(props: SVGProps) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} +export default EosIconsBubbleLoading; diff --git a/packages/example/pages/docs/change-log.en-US.mdx b/packages/example/pages/docs/change-log.en-US.mdx index b1919cc..91bd786 100644 --- a/packages/example/pages/docs/change-log.en-US.mdx +++ b/packages/example/pages/docs/change-log.en-US.mdx @@ -2,6 +2,12 @@ title: Change Log --- +## 1.0.0 + +1. fix: `loadingElement` position problem +2. fix: Image enlargement limit optimization +3. fix: In a few models, the picture cannot be previewed + ## 1.0.0-beta.8 1. fix: Inaccurate zoom position after `onScale` API call diff --git a/packages/example/pages/docs/change-log.zh-CN.mdx b/packages/example/pages/docs/change-log.zh-CN.mdx index e22b85f..53da7d0 100644 --- a/packages/example/pages/docs/change-log.zh-CN.mdx +++ b/packages/example/pages/docs/change-log.zh-CN.mdx @@ -2,6 +2,12 @@ title: Change Log --- +## 1.0.0 + +1. fix: `loadingElement` 位置问题 +2. fix: 图片放大限制优化 +3. fix: 个别机型中图片无法预览问题 + ## 1.0.0-beta.8 1. fix: `onScale` API 调用后缩放位置不准确的问题 diff --git a/packages/example/pages/docs/getting-started.en-US.mdx b/packages/example/pages/docs/getting-started.en-US.mdx index 50c5186..a605526 100644 --- a/packages/example/pages/docs/getting-started.en-US.mdx +++ b/packages/example/pages/docs/getting-started.en-US.mdx @@ -178,7 +178,7 @@ When loading images whose aspect ratio exceeds `3` times, the mobile device will `` child components can be of the regular `React.HTMLAttributes` type, such as ``, `
`, etc. -If it is a custom component, you need to ensure that `onClick` (desktop), `onTouchStart` and `onTouchEnd` (mobile) events can be triggered normally, and forward `ref` to `HTMLElement` to ensure the correctness of opening and closing the animation source. +If it is a custom component, you need to ensure that `onClick` event can be triggered normally, and forward `ref` to `HTMLElement` to ensure the correctness of opening and closing the animation source. ```jsx @@ -299,7 +299,7 @@ Add the `overlayRender` function to `` to implement custom nodes. ### Loop preview -Add parameter `loop` on `` to change the number of loop previews. Set to `boolean` to enable and disable, set to `number` type to reach a specific number to enable loop preview, the default value is `3` sheets: +Add parameter `loop` on `` to change the number of loop previews. Set to `boolean` to enable and disable, set to `number` type to exceed the specific number to enable loop preview, the default value is `3` sheets: ```jsx diff --git a/packages/example/pages/docs/getting-started.zh-CN.mdx b/packages/example/pages/docs/getting-started.zh-CN.mdx index 27c6283..829aaf0 100644 --- a/packages/example/pages/docs/getting-started.zh-CN.mdx +++ b/packages/example/pages/docs/getting-started.zh-CN.mdx @@ -177,7 +177,7 @@ export default function MyComponent() { `` 子组件可以是常规 `React.HTMLAttributes` 类型,如 ``、`
` 等。 -如果是自定义组件则需要保证 `onClick` (桌面端),`onTouchStart` 和 `onTouchEnd` (移动端)事件能正常触发,转发 `ref` 到 `HTMLElement` 上保证打开/关闭动画源的正确性。 +如果是自定义组件则需要保证 `onClick` 事件能正常触发,转发 `ref` 到 `HTMLElement` 上保证打开/关闭动画源的正确性。 ```jsx @@ -297,7 +297,7 @@ function MyComponent() { ### 循环预览 -在 `` 上添加参数 `loop` 可以更改循环预览数量。设为 `boolean` 启用/关闭,设为 `number` 类型则达到具体数量以开启循环预览,默认值为 `3` 张: +在 `` 上添加参数 `loop` 可以更改循环预览数量。设为 `boolean` 启用/关闭,设为 `number` 类型则超过具体数量以开启循环预览,默认值为 `3` 张: ```jsx diff --git a/packages/react-photo-view/package.json b/packages/react-photo-view/package.json index 225dbd7..9d11b9c 100644 --- a/packages/react-photo-view/package.json +++ b/packages/react-photo-view/package.json @@ -1,6 +1,6 @@ { "name": "react-photo-view", - "version": "1.0.0-beta.8", + "version": "1.0.0", "description": "An exquisite React photo preview component", "author": "MinJieLiu", "license": "Apache-2.0", diff --git a/packages/react-photo-view/src/Photo.tsx b/packages/react-photo-view/src/Photo.tsx index 1422ab6..edc66a8 100644 --- a/packages/react-photo-view/src/Photo.tsx +++ b/packages/react-photo-view/src/Photo.tsx @@ -62,7 +62,8 @@ export default function Photo({ alt="" {...restProps} /> - {!loaded && (loadingElement || )} + {!loaded && + ({loadingElement} || )} ); } @@ -70,11 +71,7 @@ export default function Photo({ if (brokenElement) { return ( - {typeof brokenElement === 'function' - ? brokenElement({ - src, - }) - : brokenElement} + {typeof brokenElement === 'function' ? brokenElement({ src }) : brokenElement} ); } diff --git a/packages/react-photo-view/src/PhotoBox.tsx b/packages/react-photo-view/src/PhotoBox.tsx index f4eff08..d5cda2b 100644 --- a/packages/react-photo-view/src/PhotoBox.tsx +++ b/packages/react-photo-view/src/PhotoBox.tsx @@ -204,10 +204,7 @@ export default function PhotoBox({ // 初始移动距离不足 if (isStillX && isStillY) { // 方向记录上次移动距离,以便平滑过渡 - updateState({ - lastCX: nextClientX, - lastCY: nextClientY, - }); + updateState({ lastCX: nextClientX, lastCY: nextClientY }); return; } // 设置响应状态 @@ -233,33 +230,22 @@ export default function PhotoBox({ // 横向边缘触发、背景触发禁用当前滑动 if (currentReach === 'x' || maskTouched) { updateState({ reach: 'x' }); - } else { - // 目标倍数 - const toScale = limitScale( - scale + ((currentTouchLength - touchLength) / 100 / 2) * scale, - naturalWidth / width, - scaleBuffer, - ); - // 导出变量 - expose({ scale: toScale }); - updateState({ - touchLength: currentTouchLength, - reach: currentReach, - scale: toScale, - ...getPositionOnMoveOrScale( - x, - y, - width, - height, - scale, - toScale, - nextClientX, - nextClientY, - offsetX, - offsetY, - ), - }); + return; } + // 目标倍数 + const toScale = limitScale( + scale + ((currentTouchLength - touchLength) / 100 / 2) * scale, + naturalWidth / width, + scaleBuffer, + ); + // 导出变量 + expose({ scale: toScale }); + updateState({ + touchLength: currentTouchLength, + reach: currentReach, + scale: toScale, + ...getPositionOnMoveOrScale(x, y, width, height, scale, toScale, nextClientX, nextClientY, offsetX, offsetY), + }); } }, { @@ -302,7 +288,6 @@ export default function PhotoBox({ // 重置响应状态 initialTouchRef.current = 0; if ((touched || maskTouched) && isActive) { - const hasMove = CX !== nextClientX || CY !== nextClientY; updateState({ touched: false, maskTouched: false, @@ -310,15 +295,18 @@ export default function PhotoBox({ stopRaf: false, reach: undefined, }); + const safeScale = limitScale(scale, naturalWidth / width); // Go - slideToPosition(x, y, lastX, lastY, width, height, scale, lastScale, rotate, touchTime); + slideToPosition(x, y, lastX, lastY, width, height, scale, safeScale, lastScale, rotate, touchTime); onReachUp(nextClientX, nextClientY); // 触发 Tap 事件 - if (!hasMove) { + if (CX === nextClientX && CY === nextClientY) { if (touched) { handlePhotoTap(nextClientX, nextClientY); - } else if (maskTouched) { + return; + } + if (maskTouched) { onMaskTap(nextClientX, nextClientY); } } @@ -394,11 +382,7 @@ export default function PhotoBox({ if (!reach) { // 限制最大倍数和最小倍数 const toScale = limitScale(scale - e.deltaY / 100 / 2, naturalWidth / width); - updateState({ - CX: e.clientX, - CY: e.clientY, - stopRaf: true, - }); + updateState({ stopRaf: true }); onScale(toScale, e.clientX, e.clientY); } } diff --git a/packages/react-photo-view/src/PhotoSlider.tsx b/packages/react-photo-view/src/PhotoSlider.tsx index b40b7be..d3218ea 100644 --- a/packages/react-photo-view/src/PhotoSlider.tsx +++ b/packages/react-photo-view/src/PhotoSlider.tsx @@ -213,11 +213,7 @@ export default function PhotoSlider(props: IPhotoSliderProps) { }); function handlePhotoTap(closeable: boolean | undefined) { - return closeable - ? close() - : updateState({ - overlay: !overlay, - }); + return closeable ? close() : updateState({ overlay: !overlay }); } function handleResize() { diff --git a/packages/react-photo-view/src/PhotoView.tsx b/packages/react-photo-view/src/PhotoView.tsx index be645ec..04c0c53 100644 --- a/packages/react-photo-view/src/PhotoView.tsx +++ b/packages/react-photo-view/src/PhotoView.tsx @@ -1,11 +1,10 @@ import type React from 'react'; -import { Children, cloneElement, useContext, useEffect, useRef, useState } from 'react'; +import { Children, cloneElement, useContext, useEffect, useRef } from 'react'; import useInitial from './hooks/useInitial'; import useMethods from './hooks/useMethods'; import type { PhotoContextType } from './photo-context'; import PhotoContext from './photo-context'; import type { PhotoRenderParams } from './types'; -import isTouchDevice from './utils/isTouchDevice'; export interface PhotoViewProps { /** @@ -33,10 +32,6 @@ export interface PhotoViewProps { const PhotoView: React.FC = ({ src, render, width, height, children }) => { const photoContext = useContext(PhotoContext); const key = useInitial(() => photoContext.nextId()); - const [position, updatePosition] = useState({ - clientX: undefined as number | undefined, - clientY: undefined as number | undefined, - }); const originRef = useRef(null); useEffect(() => { @@ -58,21 +53,6 @@ const PhotoView: React.FC = ({ src, render, width, height, child render(props: PhotoRenderParams) { return render && render(props); }, - touchStart(e: React.TouchEvent) { - const { clientX, clientY } = e.touches[0]; - updatePosition({ - clientX, - clientY, - }); - invokeChildrenFn('onTouchStart', e); - }, - touchEnd(e: React.TouchEvent) { - const { clientX, clientY } = e.changedTouches[0]; - if (position.clientX === clientX && position.clientY === clientY) { - photoContext.show(key); - } - invokeChildrenFn('onTouchEnd', e); - }, click(e: React.MouseEvent) { photoContext.show(key); invokeChildrenFn('onClick', e); @@ -91,18 +71,7 @@ const PhotoView: React.FC = ({ src, render, width, height, child }, [src]); if (children) { - return Children.only( - cloneElement( - children, - isTouchDevice - ? { - onTouchStart: fn.touchStart, - onTouchEnd: fn.touchEnd, - ref: originRef, - } - : { onClick: fn.click, ref: originRef }, - ), - ); + return Children.only(cloneElement(children, { onClick: fn.click, ref: originRef })); } return null; }; diff --git a/packages/react-photo-view/src/hooks/useScrollPosition.ts b/packages/react-photo-view/src/hooks/useScrollPosition.ts index 28dc68a..67ed643 100644 --- a/packages/react-photo-view/src/hooks/useScrollPosition.ts +++ b/packages/react-photo-view/src/hooks/useScrollPosition.ts @@ -1,7 +1,6 @@ import { computePositionEdge } from '../utils/edgeHandle'; import getPositionOnMoveOrScale from '../utils/getPositionOnMoveOrScale'; import getRotateSize from '../utils/getRotateSize'; -import { limitScale } from '../utils/limitTarget'; import { defaultSpeed, maxTouchTime } from '../variables'; import useMethods from './useMethods'; @@ -38,23 +37,21 @@ export default function useScrollPosition boolean width: number, height: number, scale: number, + safeScale: number, lastScale: number, rotate: number, touchedTime: number, ) => { const [currentWidth, currentHeight] = getRotateSize(rotate, width, height); // 开始状态下边缘触发状态 - const [beginEdgeX, beginX] = computePositionEdge(x, scale, currentWidth, innerWidth); - const [beginEdgeY, beginY] = computePositionEdge(y, scale, currentHeight, innerHeight); + const [beginEdgeX, beginX] = computePositionEdge(x, safeScale, currentWidth, innerWidth); + const [beginEdgeY, beginY] = computePositionEdge(y, safeScale, currentHeight, innerHeight); const moveTime = Date.now() - touchedTime; - // 缩放调整至安全范围 - const nextScale = limitScale(scale); - // 时间过长、超出安全范围的情况下不执行滚动逻辑,恢复安全范围 - if (moveTime >= maxTouchTime || nextScale != scale || Math.abs(lastScale - scale) > 1) { + if (moveTime >= maxTouchTime || safeScale != scale || Math.abs(lastScale - scale) > 1) { // 计算中心缩放点 - const { x: nextX, y: nextY } = getPositionOnMoveOrScale(x, y, width, height, scale, nextScale); + const { x: nextX, y: nextY } = getPositionOnMoveOrScale(x, y, width, height, scale, safeScale); const targetX = beginEdgeX ? beginX : nextX !== x ? nextX : null; const targetY = beginEdgeY ? beginY : nextY !== y ? nextY : null; @@ -64,8 +61,8 @@ export default function useScrollPosition boolean if (targetY !== null) { easeOutMove(y, targetY, callback.Y); } - if (nextScale != scale) { - easeOutMove(scale, nextScale, callback.S); + if (safeScale != scale) { + easeOutMove(scale, safeScale, callback.S); } return; } diff --git a/packages/react-photo-view/src/utils/isTouchDevice.ts b/packages/react-photo-view/src/utils/isTouchDevice.ts index 29b90c7..d97d07b 100644 --- a/packages/react-photo-view/src/utils/isTouchDevice.ts +++ b/packages/react-photo-view/src/utils/isTouchDevice.ts @@ -1,6 +1,6 @@ /** * 是否支持触摸设备 */ -const isTouchDevice = typeof document !== 'undefined' && 'ontouchstart' in document.documentElement; +const isTouchDevice = typeof window !== 'undefined' && 'ontouchstart' in window; export default isTouchDevice;