From bac23e459cbe5e1e53a75574fa8f71fb7fd497a9 Mon Sep 17 00:00:00 2001 From: oasis <12181600+oasis-cloud@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:17:23 +0800 Subject: [PATCH] refactor: sticky (#2468) --- src/packages/sticky/sticky.taro.tsx | 75 ++++++++++++++--------------- src/packages/sticky/sticky.tsx | 67 ++++++++++++-------------- src/utils/get-scroll-parent.ts | 2 +- 3 files changed, 68 insertions(+), 76 deletions(-) diff --git a/src/packages/sticky/sticky.taro.tsx b/src/packages/sticky/sticky.taro.tsx index d0a627aca4..d6f8e8d3ad 100644 --- a/src/packages/sticky/sticky.taro.tsx +++ b/src/packages/sticky/sticky.taro.tsx @@ -1,18 +1,18 @@ import React, { - FunctionComponent, - useRef, - useState, - useMemo, CSSProperties, + FunctionComponent, useCallback, useEffect, + useMemo, + useRef, + useState, } from 'react' import classNames from 'classnames' import { + getEnv, + getSystemInfoSync, PageScrollObject, usePageScroll, - getSystemInfoSync, - getEnv, } from '@tarojs/taro' import { BasicComponent, ComponentDefaults } from '@/utils/typings' import useWatch from '@/utils/use-watch' @@ -72,12 +72,10 @@ export const Sticky: FunctionComponent> = (props) => { width: '', } } - const style: CSSProperties = {} - if (rootRect.height) { - style.height = rootRect.height - } - if (rootRect.width) { - style.width = rootRect.width + + const style: CSSProperties = { + height: rootRect.height ?? '', + width: rootRect.width ?? '', } return style }, [fixed, rootRect.height, rootRect.width]) @@ -87,46 +85,47 @@ export const Sticky: FunctionComponent> = (props) => { return { height: '', width: '', - [position as string]: '', + [position]: '', } } - const style: CSSProperties = {} - if (rootRect.height) style.height = rootRect.height - if (rootRect.width) style.width = rootRect.width - style.transform = `translate3d(0, ${transform}px, 0)` - style[position] = threshold - style.zIndex = zIndex + const style: CSSProperties = { + height: rootRect.height ?? '', + width: rootRect.width ?? '', + transform: `translate3d(0, ${transform}px, 0)`, + [position]: threshold, + zIndex, + } return style }, [fixed, rootRect.height, rootRect.width, transform, position]) const handleScroll: any = async (scrollTop: number) => { const curRootRect = await getRectByTaro(rootRef.current) const stickyRect = await getRectByTaro(stickyRef.current) - if (curRootRect && stickyRect) { - setRootRect(curRootRect) - if (position === 'top') { - if (container) { - const containerRect = await getRectByTaro(container.current) - const difference = - containerRect.bottom - threshold - curRootRect.height - const curTransform = difference < 0 ? difference : 0 - setTransform(curTransform) - const curFixed = - threshold > curRootRect.top && containerRect.bottom > 0 - setFixed(curFixed) - } else { - setFixed(threshold > curRootRect.top) - } + if (!curRootRect || !stickyRect) { + console.warn('getRectByTaro获取失败', { stickyRect, curRootRect }) + return + } + + setRootRect(curRootRect) + + if (position === 'top') { + if (container) { + const containerRect = await getRectByTaro(container.current) + const difference = containerRect.bottom - threshold - curRootRect.height + const curTransform = difference < 0 ? difference : 0 + setTransform(curTransform) + const curFixed = threshold > curRootRect.top && containerRect.bottom > 0 + setFixed(curFixed) } else { - const windowHeight = getSystemInfoSync().windowHeight - setFixed(windowHeight - threshold < curRootRect.bottom) + setFixed(threshold > curRootRect.top) } } else { - console.warn('getRectByTaro获取失败', { stickyRect, curRootRect }) + const windowHeight = getSystemInfoSync().windowHeight + setFixed(windowHeight - threshold < curRootRect.bottom) } } const getElement = useCallback(() => { - return getScrollParent(rootRef.current as HTMLElement) + return getScrollParent(rootRef.current) }, []) useEffect(() => { diff --git a/src/packages/sticky/sticky.tsx b/src/packages/sticky/sticky.tsx index da20efcdc9..de7b8b65c7 100644 --- a/src/packages/sticky/sticky.tsx +++ b/src/packages/sticky/sticky.tsx @@ -1,10 +1,10 @@ import React, { + CSSProperties, FunctionComponent, - useEffect, useCallback, + useEffect, useRef, useState, - CSSProperties, } from 'react' import classNames from 'classnames' import { getScrollParent } from '@/utils/get-scroll-parent' @@ -58,14 +58,15 @@ export const Sticky: FunctionComponent> = (props) => { useEffect(() => { if (position === 'top') return - const containerEle = container?.current as HTMLElement + const containerEle = container && container.current + const rootEle = rootRef.current + const stickyEle = stickyRef.current - if (!rootRef.current && !containerEle) return - const rootRect = getRect(rootRef.current as Element) + if (!rootEle && !containerEle) return + const rootRect = getRect(rootEle) const containerRect = getRect(containerEle) const clientHeight = document.documentElement.clientHeight - const stCurrent = stickyRef.current as Element - const stickyRect = getRect(stCurrent) + const stickyRect = getRect(stickyEle) let fixed = clientHeight - threshold < rootRect.bottom if (containerEle) { fixed = @@ -82,21 +83,19 @@ export const Sticky: FunctionComponent> = (props) => { setIsFixed(fixed) }, [position, container, threshold]) const handleScroll = useCallback(() => { - const containerEle = container?.current as HTMLElement + const containerEle = container && container.current + const rootEle = rootRef.current + const stickyEle = stickyRef.current + if (!rootEle && !containerEle) return - if (!rootRef.current && !containerEle) return - - const rootRect = getRect(rootRef.current as Element) - const stCurrent = stickyRef.current as Element - const stickyRect = getRect(stCurrent) + const rootRect = getRect(rootEle) + const stickyRect = getRect(stickyEle) const containerRect = getRect(containerEle) if (rootRect.height) { - setRootStyle((prev) => { - return { - ...prev, - height: rootRect.height, - } - }) + setRootStyle((prev) => ({ + ...prev, + height: rootRect.height, + })) } const getFixed = () => { @@ -119,22 +118,16 @@ export const Sticky: FunctionComponent> = (props) => { } const getTransform = (): CSSProperties => { - if (position === 'top') { - if (containerEle) { - const diff = containerRect.bottom - threshold - stickyRect.height - const transform = diff < 0 ? diff : 0 - return { transform: `translate3d(0, ${transform}px, 0)` } - } - return {} + if (position === 'top' && containerEle) { + const diff = containerRect.bottom - threshold - stickyRect.height + const transform = diff < 0 ? diff : 0 + return { transform: `translate3d(0, ${transform}px, 0)` } } - if (position === 'bottom') { - if (containerEle) { - const clientHeight = document.documentElement.clientHeight - const diff = containerRect.bottom - (clientHeight - threshold) - const transform = diff < 0 ? diff : 0 - return { transform: `translate3d(0, ${transform}px, 0)` } - } - return {} + if (position === 'bottom' && containerEle) { + const clientHeight = document.documentElement.clientHeight + const diff = containerRect.bottom - (clientHeight - threshold) + const transform = diff < 0 ? diff : 0 + return { transform: `translate3d(0, ${transform}px, 0)` } } return {} } @@ -153,10 +146,10 @@ export const Sticky: FunctionComponent> = (props) => { onChange && onChange(isFixed) }) useEffect(() => { - const el = getElement() as HTMLElement | Window - el.addEventListener('scroll', handleScroll, false) + const el = getElement() + el?.addEventListener('scroll', handleScroll, false) return () => { - el.removeEventListener('scroll', handleScroll) + el?.removeEventListener('scroll', handleScroll) } }, [getElement, handleScroll]) diff --git a/src/utils/get-scroll-parent.ts b/src/utils/get-scroll-parent.ts index 2273d8b362..ca226df4a1 100644 --- a/src/utils/get-scroll-parent.ts +++ b/src/utils/get-scroll-parent.ts @@ -12,7 +12,7 @@ function isElement(node: Element) { } export function getScrollParent( - el: Element, + el: Element | null | undefined, root: ScrollElement | null | undefined = defaultRoot ): Window | Element | null | undefined { let node = el