浮动底部按钮的实现,跟随内容移动与固定
2023-06-16 16:08 前端小白的江湖路 阅读(687) 评论(0) 收藏 举报背景
未超过一屏时,底部按钮跟随内容
超过一屏时,底部按钮固定在底部
原理
我们需要同时监听DOM变动函数以及窗口大小变化,大于一屏时,添加底部按钮fixed布局
小于一屏时移除
实现
import React, { useState, useRef, useEffect, useCallback } from "react";
import throttle from "lodash/throttle";
import cx from "classnames";
import "./index.scss";
interface IProps {
content: React.ReactNode;
footer: React.ReactNode;
containerClassName?: string;
contentClassName?: string;
footerClassName?: string;
throttleTime?: number;
}
const FloatFooter: React.FC<IProps> = (props) => {
const {
content,
footer,
containerClassName,
contentClassName,
footerClassName,
throttleTime = 500,
} = props;
const containerRef = useRef<HTMLDivElement>(null);
const contentRef = useRef<HTMLDivElement>(null);
const footerRef = useRef<HTMLDivElement>(null);
const [fixed, setFixed] = useState<boolean>(false);
const [footerHeight, setFooterHeight] = useState<number>(0);
const handleHeightChange = useCallback(
throttle(
() => {
const contentElement = contentRef.current;
const footerElement = footerRef.current;
if (!contentElement || !footerElement) return;
const contentElementHeight = contentElement.clientHeight;
const viewportHeight = document.documentElement.clientHeight;
if (contentElementHeight > viewportHeight) {
setFixed(true);
setFooterHeight(footerElement.clientHeight);
} else {
setFixed(false);
setFooterHeight(0);
}
},
throttleTime,
{ trailing: false }
),
[]
);
useEffect(() => {
handleHeightChange();
window.addEventListener("resize", handleHeightChange);
const observer = new MutationObserver(handleHeightChange);
const observerConfig = { childList: true, subtree: true, attributes: true, characterData: true};
if (containerRef.current) {
observer.observe(containerRef.current, observerConfig);
}
return () => {
window.removeEventListener("resize", handleHeightChange);
observer.disconnect();
};
}, []);
return (
<article
className={cx("i-container", containerClassName)}
ref={containerRef}
>
<section className={cx("i-content", contentClassName)} ref={contentRef}>
{content}
{fixed && <div style={{ height: `${footerHeight}px` }}></div>}
</section>
<footer
className={cx("i-footer", footerClassName, { "i-fixed-footer": fixed })}
ref={footerRef}
>
{footer}
</footer>
</article>
);
};
export default FloatFooter;
.i-fixed-footer { position: fixed; left: 0; right: 0; bottom: 0; }
PS: 常用的还有另外一种固定底部的布局
未超过一屏固定在底部,超过一屏跟随内容,附在底部。
这个多用在网站的首页,底部为通用的信息展示。
可以这样实现:
最重要的是给一个min-height 属性
1.如果使用flex,就上下布局,分散2头。
2.如果使用absolute布局,可以直接固定在底部
import React from "react"; import "./index.scss"; const FixedFooter = () => { const list = new Array(10).fill(1).map((item, index) => index); // const list = new Array(10).fill(1).map((item, index) => index); return ( <article className="main"> <section className="content"> {list.map((item) => ( <div key={item}>{item}</div> ))} </section> <footer className="footer">I am footer</footer> </article> ); }; export default FixedFooter;
.main { display: flex; flex-direction: column; justify-content: space-between; min-height: 100vh; .content { } .footer { background-color: black; color: white; } } // .main { // position: relative; // min-height: 100vh; // .content { // padding-bottom: 30px; // } // .footer { // position: absolute; // bottom: 0; // width: 100%; // height: 30px; // background-color: black; // color: white; // } // }
浙公网安备 33010602011771号