Сделать плавающий блок React
Доброго времени суток!
Нужно сделать плавающий div с сообщением, без jQuery, чтобы при прокрутке ниже хедера это сообщение крепилось в верху экрана
Можно без рефов , на хуках, с функциональными компонентами, любыми способами только без jQuery.
Думал, что нужно взять координаты сообщения и когда верхние будут отрицательными добавлять css класс с position: fixed.
import React, { useState, useRef } from "react";
import "./styles.css";
import { observable, computed } from "mobx";
import { observer } from "mobx-react";
const Header = () => (
<div className="header">
<h1>Header</h1>
</div>
);
const Message = React.forwardRef((props, ref) => {
return (
<div ref={ref} className="message">
<h2>Message</h2>
</div>
);
});
const Space = () => <div className="space" />;
@observer
class App extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
@observable sticky = this.ref.current.getBoundingClientRect();
someMethod() {}
render() {
return (
<div className="App">
<Header />
<Message ref={this.ref} />
<button
onClick={() => {
console.log(this.sticky);
this.ref.current.style.display = "flex";
}}
>
add message
</button>
<button
onClick={() => {
console.log(this.sticky);
this.ref.current.style.display = "none";
}}
>
remove message
</button>
<Space />
//получается сделать через событие
<button
onClick={() => {
if (this.ref.current.getBoundingClientRect().top < 0) {
this.ref.current.classList.add("sticky");
}
}}
>
add sticky
</button>
</div>
);
}
}
export default App;
css:
* {
margin: 0;
padding: 0;
}
.App {
font-family: sans-serif;
text-align: center;
}
.header {
height: 100px;
background: blue;
display: flex;
justify-content: center;
align-items: center;
}
.space {
height: 500px;
}
.message {
display: none;
background: green;
height: 70px;
justify-content: center;
align-items: center;
}
.sticky {
width: 100%;
position: fixed;
top: 0;
}
Ответы (1 шт):
Вручную делать sticky-элемент с помoщью JS довольно муторно и особого смысла не имеет так как большинство современных браузеров уже давно поддерживают position sticky:
div {
position: sticky;
top: 20px;
}
Элемент с липкой позицией — это элемент, у которого значение вычисленного position является sticky. Он рассматривается как относительно позиционированный до тех пор, пока содержащий его блок не пересечёт указанный порог (например, установка top в значение, отличное от auto) внутри его корня потока (или в контейнере, в котором он прокручивается), после чего он обрабатывается как «застрявший» до тех пор, пока не встретит противоположный край содержащего его блока.
Отвечая на Ваш вопрос:
// простой набросок подхода
const headerRef = useRef()
const scrollHandler = () => {
const bcr = headerRef.current.getBoundingClientRect()
console.log(bcr)
}
useEffect(() => {
window.addEventListner("scroll", scrollHandler, false)
return () => window.removeEventListner("scroll", scrollHandler, false)
}, [])
return <div ref={headerRef} class="header"></div>
Метод getBoundingClientRect() в сочетании с событием onscroll даст вам возможность понять где именно в каждый конкретный момент находиться нужный вам элемент относительно viewport'a.
ВАЖНО: Вам нужно использовать debounce что бы ограничить количество срабатываний функции scrollHandler, иначе это приведет к просадке производительности Вашего приложения.