From 26f8a264a35ddcd02a49d3b2789d9fc13241cb30 Mon Sep 17 00:00:00 2001 From: master1lan <278457198@qq.com> Date: Sun, 19 Feb 2023 17:11:00 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20fix(custom):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E5=9B=BE=E7=89=87=E9=A1=B5=E9=9D=A2=E9=97=AA?= =?UTF-8?q?=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当点击图片时,滚动条会被隐藏导致整体页面重拍;现在已经修复 --- src/routers/photo/item/modal.tsx | 2 + src/utils/dom/index.ts | 71 ++++++++++++++++++++++++++++++++ src/utils/hooks/match.ts | 17 ++++++++ 3 files changed, 90 insertions(+) create mode 100644 src/utils/dom/index.ts diff --git a/src/routers/photo/item/modal.tsx b/src/routers/photo/item/modal.tsx index abc3f09..ac12fef 100644 --- a/src/routers/photo/item/modal.tsx +++ b/src/routers/photo/item/modal.tsx @@ -3,6 +3,7 @@ import { PhotoSlider } from "react-photo-view"; import "react-photo-view/dist/react-photo-view.css"; import { useEffect } from "react"; import { useLocation } from "react-router-dom"; +import { useBodyScrollHide } from "@utils/hooks/match"; type ModalType = { images: basicImageType[]; open: boolean; @@ -29,6 +30,7 @@ export default function ImgModals(props: ModalType) { }; } }, [open]); + useBodyScrollHide(open); return ( ({ src: item.src, key: index }))} diff --git a/src/utils/dom/index.ts b/src/utils/dom/index.ts new file mode 100644 index 0000000..286c412 --- /dev/null +++ b/src/utils/dom/index.ts @@ -0,0 +1,71 @@ +/** + * 给元素style添加属性。 + */ +export const ObjectToHtmlStyle = ( + obj: React.CSSProperties, + ele: HTMLElement +) => { + Object.entries(obj).forEach(([key, value]) => { + if (value) { + //@ts-ignore + ele.style[key] = value; + } + }); +}; + +let _ScrollBarWidthCached: number | null = null; + +function hasScrollbar(): boolean { + return ( + document.body.scrollHeight > + (window.innerHeight || document.documentElement.clientHeight) + ); +} +export function getScrollBarSize(): number { + if (!hasScrollbar()) { + _ScrollBarWidthCached = 0; + } + if (typeof _ScrollBarWidthCached === "number") { + return _ScrollBarWidthCached; + } + const inner = document.createElement("div"); + ObjectToHtmlStyle( + { + width: "100%", + height: "200px", + }, + inner + ); + const outer = document.createElement("div"); + ObjectToHtmlStyle( + { + position: "absolute", + top: "0", + left: "0", + pointerEvents: "none", + visibility: "hidden", + width: "200px", + height: "150px", + overflow: "hidden", + }, + outer + ); + outer.appendChild(inner); + document.body.appendChild(outer); + const widthContained = inner.offsetWidth; + ObjectToHtmlStyle( + { + overflow: "scroll", + }, + outer + ); + let widthScroll = inner.offsetWidth; + + if (widthContained === widthScroll) { + widthScroll = outer.clientWidth; + } + + document.body.removeChild(outer); + _ScrollBarWidthCached = widthContained - widthScroll; + return _ScrollBarWidthCached; +} diff --git a/src/utils/hooks/match.ts b/src/utils/hooks/match.ts index aade130..252268d 100644 --- a/src/utils/hooks/match.ts +++ b/src/utils/hooks/match.ts @@ -1,4 +1,6 @@ import { Breakpoint, useMediaQuery, useTheme } from "@mui/material"; +import { getScrollBarSize } from "@utils/dom"; +import { useEffect } from "react"; /** * @description 获知当前屏幕处于哪种大小 @@ -16,3 +18,18 @@ export const useScreenMatchSize = (size: Breakpoint) => { `@672w_378h_1c_!web-search-common-cover`; //首页up头像大小 `@96w_96h_1s.webp`; + +export const useBodyScrollHide = (hidden: boolean) => { + useEffect(() => { + const ScrollSize = getScrollBarSize(), + bodyStyle = document.body.style; + if (hidden) { + bodyStyle.overflow = "hidden"; + bodyStyle.paddingRight = `${ScrollSize}px`; + } + return () => { + bodyStyle.overflow = ""; + bodyStyle.paddingRight = ""; + }; + }, [hidden]); +};