浮动底部按钮的实现,跟随内容移动与固定
2023-06-16 16:08 前端小白的江湖路 阅读(562) 评论(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; // } // }