本篇内容介绍了“React如何实现具备吸顶和吸底功能组件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
具体要求:
需要可以设置是
吸顶
还是吸底
。吸顶
可以设置距离视窗顶部的位置,吸顶
可以设置距离视窗底部的位置。可以对正常组件都生效,不影响组件自身的样式。
实现
组件主要是为了 吸顶
或者 吸底
功能,那么就命名为 AutoFixed
。
主要实现逻辑:需要判断自身在视窗内的位置与设置的 吸顶
或者 吸底
位置是否匹配,匹配上了则可以进行 吸顶
或者 吸底
。
获取自身位置一般可以用 滚动的位置
和 自身距离页面顶部
的位置来判断,但实现起来会麻烦一些,IntersectionObserver
也很好用,而且性能会更好,因此这里将直接使用 IntersectionObserver
来处理。
下面,我们先实现一个基于 IntersectionObserver
实现的判断位置的 hook
。
定义 props 类型:
import { RefObject } from "react";type Props = { el: React.RefObject<Element>; options?: IntersectionObserverInit;};
可接受参数:
el
: React 的 ref
实例,被判断判断位置的 DOM 元素。 options
: IntersectionObserver 构造函数的初始化参数。
具体实现:
import React, { useEffect, useState } from "react";export function useIntersection(props: Props): boolean { const { el, options } = props; // 是否到了指定位置区域 const [intersection, setIntersection] = useState(true); useEffect(() => { if (!el.current) return; // 初始化 IntersectionObserver 实例 const intersectionObserver = new IntersectionObserver( function (entries) { setIntersection(entries[0].intersectionRatio === 1); }, { ...options, threshold: [1] } ); // 开始监听 intersectionObserver.observe(el.current); return (): void => { // 销毁 intersectionObserver.disconnect(); }; }, [el.current]); return intersection;}
现在实现了一个可以根据传入的参数来控制否到了指定位置区域的 hook :useIntersection
。
useIntersection
只是对 IntersectionObserver
的简单封装,并没有复杂实现,具体作用就是用于判断某个元素是否进入了 可视窗口
,想了解更多可以点击去查看它的MDN文档。
下面再来实现我们要实现的具备吸顶和吸底功能的组件:AutoFixed
。
参数定义:
export type AutoFixedProps = React.ImgHTMLAttributes<HTMLDivElement> & { top?: string; bottom?: string; alwaysFixed?: boolean; zIndex?: number; children: React.ReactNode; height: number | string; root?: Element | Document | null; fixedClassName?: string; fixedStyle?: React.CSSProperties; onFixedChange?: (isFixed: boolean) => void;};
可接受参数 基于 React.HtmlHTMLAttributes<HTMLDivElement>
,也就是继承了 div
的默认属性。
其他自定义参数说明:
top
吸顶距离,元素顶部
距离视窗顶部
小于等于top
时,进行吸顶。bottom
吸底部距离,元素底部
距离视窗底部
大于等于bottom
时,进行吸底。注意逻辑是和吸顶
相反。alwaysFixed
,用于支持默认就要一直吸顶或者吸底的情况,需要配合top
和bottom
来使用。zIndex
控制吸顶或者吸底时的样式层级。children
children
元素是正常的 React 组件即可。height
被包裹元素的高度.也就是children
元素 的高度。root
,相对视窗的目标元素,也就是可以控制在某个区域内进行吸顶和吸底,但因为这里是用的fixed
定位,如果需要设置root
时,需要改变成absolute
定位。fixedClassName
吸顶和吸底的时候需要动态添加的className
。fixedStyle
吸顶和吸底的时候需要动态添加的样式
。onFixedChange
吸顶和吸底的时候告诉外界。
具体实现:
import React, { useRef, useEffect } from "react";import { useIntersection } from "../../components/hooks/use-intersection";export const AutoFixed = (props: AutoFixedProps) => { const { alwaysFixed, top, bottom, style, height, root, zIndex = 100, children, className, fixedClassName, fixedStyle, onFixedChange, ...rest } = props; // `bottom` 值存在时,表面要悬浮底部 const isFiexdTop = !bottom; const wrapperRef = useRef<HTMLDivElement>(null); // 设置监听参数控制:top 为吸顶距离,bottom 为吸底距离 const options = { rootMargin: isFiexdTop ? `-${top || "0px"} 0px 1000000px 0px` : `0px 0px -${bottom || "0px"} 0px`, // 设置root root, } as IntersectionObserverInit; // 是否悬浮 const intersection = useIntersection({ el: wrapperRef, options }); const shouldFixed = alwaysFixed ? true : !intersection; useEffect(() => { // 通知外部 onFixedChange?.(shouldFixed); }, [shouldFixed, onFixedChange]); return ( <div style={{ ...style, height }} {...rest} className={`${className}${shouldFixed ? " fixedClassName" : ""}`} ref={wrapperRef} > <div style={{ height, position: shouldFixed ? "fixed" : "initial", top: isFiexdTop ? top || 0 : undefined, bottom: isFiexdTop ? undefined : bottom || 0, zIndex: zIndex, ...(shouldFixed ? fixedStyle : {}), }} > {children} </div> </div> );};
实现逻辑:
使用了
alwaysFixed
判断是否一直悬浮。默认悬浮顶部,
bottom
值存在时,表明要悬浮底部。给
useIntersection
传入监听位置控制参数。根据
useIntersection
的结果来判断是否应该吸顶
或吸底
。做了
style
样式和className
传入处理的问题,以及 zIndex 层级问题。吸顶时,不进行设置
bottom
,吸底时,不进行设置bottom
。
主要核心逻辑是第 3
点:
const options = { rootMargin: `-${top || "0px"} 0px -${bottom || "0px"} 0px`,};
rootMargin
中:-${top || "0px"}
为吸顶距离,-${bottom || "0px"}
为吸底距离。一定要是负的,正数表示延伸到了视窗外的距离,负数表示距离视窗顶部或者底部的距离。
使用方式:
<AutoFixed // 距离顶部为 20px 吸顶 top="20px" // 占位高度,也就是 children 的高度 height="20px" // fixed状态改变时 onFixedChange={(isFixed) => { console.log(`isFixed: ` + isFixed); }} // fixed状态需要添加的className fixedClassName="hello" // fixed状态需要添加的style fixedStyle={{ color: "red" }}> <div> 我是悬浮内容,高度 20px, 距离顶部为 20px 吸顶 </div></AutoFixed>
“React如何实现具备吸顶和吸底功能组件”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!