|
背景
现在手机应用经常有这样一个场景:
页面上有一个导航,导航位置在页面中间位置,当页面顶部滚动到导航位置时,导航自动吸顶,页面继续往下滚动时,它就一直在页面视窗顶部显示,当往上滚动时,经过最初位置时,导航自动复原,不再吸顶。
效果就如京东超市首页的导航栏一样:
下面我们就来具体实现这样一个组件,实现后还会再扩展延伸一下功能,因为场景也不少。
具体要求:
- 需要可以设置是还是。
- 可以设置距离视窗顶部的位置,可以设置距离视窗底部的位置。
- 可以对正常组件都生效,不影响组件自身的样式。
实现
组件主要是为了或者功能,那么就命名为。
主要实现逻辑:需要判断自身在视窗内的位置与设置的或者位置是否匹配,匹配上了则可以进行或者。
获取自身位置一般可以用和的位置来判断,但实现起来会麻烦一些,也很好用,而且性能会更好,因此这里将直接使用来处理。
下面,我们先实现一个基于实现的判断位置的。
定义 props 类型:- import { RefObject } from "react";
- type Props = {
- el: React.RefObject<Element>;
- options?: IntersectionObserverInit;
- };
复制代码 可接受参数:: React 的实例,被判断判断位置的 DOM 元素。: 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 :。只是对的简单封装,并没有复杂实现,具体作用就是用于判断某个元素是否进入了,想了解更多可以点击去查看它的MDN文档。
下面再来实现我们要实现的具备吸顶和吸底功能的组件:。
参数定义:- export type AutoFixedProps = React.ImgHTMLAttributes<HTMLDivElement> & {
- /** 吸顶距离 */
- top?: string;
- /** 吸底距离 */
- bottom?: string;
- /** 是否一直吸顶或者吸底 */
- alwaysFixed?: boolean;
- zIndex?: number;
- children: React.ReactNode;
- /** 元素框高度 */
- height: number | string;
- /** 相对的目标元素,因为是用的 fixed 定位,记得做相应处理。 */
- root?: Element | Document | null;
- /** 固定的时候才有的className */
- fixedClassName?: string;
- /** 固定的时候才有的样式 */
- fixedStyle?: React.CSSProperties;
- /** fixed状态改变时调用 */
- onFixedChange?: (isFixed: boolean) => void;
- };
复制代码 可接受参数 基于- React.HtmlHTMLAttributes<HTMLDivElement>
复制代码 ,也就是继承了的默认属性。
其他自定义参数说明:
- 吸顶距离,距离小于等于时,进行吸顶。
- 吸底部距离,距离大于等于时,进行吸底。注意逻辑是和相反。
- ,用于支持默认就要一直吸顶或者吸底的情况,需要配合和来使用。
- 控制吸顶或者吸底时的样式层级。
- 元素是正常的 React 组件即可。
- 被包裹元素的高度.也就是元素 的高度。
- ,相对视窗的目标元素,也就是可以控制在某个区域内进行吸顶和吸底,但因为这里是用的定位,如果需要设置时,需要改变成定位。
- 吸顶和吸底的时候需要动态添加的。
- 吸顶和吸底的时候需要动态添加的。
- 吸顶和吸底的时候告诉外界。
具体实现:- 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>
- );
- };
复制代码 实现逻辑:
- 使用了判断是否一直悬浮。
- 默认悬浮顶部,值存在时,表明要悬浮底部。
- 给传入监听位置控制参数。
- 根据的结果来判断是否应该或。
- 做了样式和传入处理的问题,以及 zIndex 层级问题。
- 吸顶时,不进行设置,吸底时,不进行设置。
主要核心逻辑是第点:- const options = {
- rootMargin: `-${top || "0px"} 0px -${bottom || "0px"} 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 实现具备吸顶和吸底功能组件实例的详细内容,更多关于React吸顶吸底功能的资料请关注脚本之家其它相关文章!
来源:https://www.jb51.net/article/276256.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|