React Hooks 滚动到元素
React Hooks Scroll to Element
我正在寻找使用 React 16.8.6 编写一个 React 钩子,它可以让我在单击导航项时滚动到特定的 HTML 元素部分。我有一个 Navigation
组件,它是页面上呈现的部分的同级组件。
此外,当页面滚动时,我想用 HTML 部分更新 App
的状态。
导航组件 JSX
<ul class="nav>
<li><a>Section 1</a></li>
<li><a>Section 2</a></li>
</ul>
主页中应用级组件的部分
<section className="section-1">Section 1</section>
<section className="section-2">Section 2</section>
挂钩
const [navItem, setNavItem] = React.useState(null);
const sectionRef = React.useRef(null);
// Scroll To Item
useEffect(() => {
console.log(sectionRef.current);
if (sectionRef.current) {
sectionRef.current.scrollToItem();
}
}, []);
如果您不介意使用 react-router-dom
,那么您可以跟踪历史变化并通过 hash
历史将滚动位置更新为 HTML 元素的 id
改变。这种方法的优点是您不必使用状态,也不必使用引用,并且它可以在整个应用程序中扩展(无论元素位于应用程序树中的什么位置,您都可以滚动到它们)。
工作示例:
https://fglet.codesandbox.io/(演示)
https://codesandbox.io/s/fglet(来源——不幸的是,在 codesandbox 编辑器中不起作用)
components/ScrollHandler(监听哈希历史变化的钩子,搜索与位于哈希中的 id 匹配的元素,如果找到匹配的元素 id,然后它会滚动到元素)
import { useEffect } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
const ScrollHandler = ({ location }) => {
useEffect(() => {
const element = document.getElementById(location.hash));
setTimeout(() => {
window.scrollTo({
behavior: element ? "smooth" : "auto",
top: element ? element.offsetTop : 0
});
}, 100);
}, [location]);
return null;
};
ScrollHandler.propTypes = {
location: PropTypes.shape({
pathname: PropTypes.string,
search: PropTypes.string,
hash: PropTypes.string,
state: PropTypes.any,
key: PropTypes.string
}).isRequired
};
export default withRouter(ScrollHandler);
components/Navigation(更改 url 哈希历史记录位置的链接)
import React from "react";
import { Link } from "react-router-dom";
import List from "../List";
const Navigation = () => (
<List>
{[1, 2, 3, 4, 5].map(num => (
<li key={num}>
<Link to={`/#section${num}`}>Section {num}</Link>
</li>
))}
</List>
);
export default Navigation;
components/Sections(Headline
组件包含将匹配的 id
)
import React from "react";
import Headline from "../Headline";
const Sections = () =>
[1, 2, 3, 4, 5].map(num => (
<Headline key={num} id={`#section${num}`}>
Section {num}
</Headline>
));
export default Sections;
index.js
import React from "react";
import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Container from "./components/Container";
import Navigation from "./components/Navigation";
import Sections from "./components/Sections";
import ScrollHandler from "./components/ScrollHandler";
import "./styles.css";
const App = () => (
<BrowserRouter>
<Container>
<ScrollHandler />
<Navigation />
<Sections />
</Container>
</BrowserRouter>
);
render(<App />, document.getElementById("root"));
我正在寻找使用 React 16.8.6 编写一个 React 钩子,它可以让我在单击导航项时滚动到特定的 HTML 元素部分。我有一个 Navigation
组件,它是页面上呈现的部分的同级组件。
此外,当页面滚动时,我想用 HTML 部分更新 App
的状态。
导航组件 JSX
<ul class="nav>
<li><a>Section 1</a></li>
<li><a>Section 2</a></li>
</ul>
主页中应用级组件的部分
<section className="section-1">Section 1</section>
<section className="section-2">Section 2</section>
挂钩
const [navItem, setNavItem] = React.useState(null);
const sectionRef = React.useRef(null);
// Scroll To Item
useEffect(() => {
console.log(sectionRef.current);
if (sectionRef.current) {
sectionRef.current.scrollToItem();
}
}, []);
如果您不介意使用 react-router-dom
,那么您可以跟踪历史变化并通过 hash
历史将滚动位置更新为 HTML 元素的 id
改变。这种方法的优点是您不必使用状态,也不必使用引用,并且它可以在整个应用程序中扩展(无论元素位于应用程序树中的什么位置,您都可以滚动到它们)。
工作示例:
https://fglet.codesandbox.io/(演示)
https://codesandbox.io/s/fglet(来源——不幸的是,在 codesandbox 编辑器中不起作用)
components/ScrollHandler(监听哈希历史变化的钩子,搜索与位于哈希中的 id 匹配的元素,如果找到匹配的元素 id,然后它会滚动到元素)
import { useEffect } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";
const ScrollHandler = ({ location }) => {
useEffect(() => {
const element = document.getElementById(location.hash));
setTimeout(() => {
window.scrollTo({
behavior: element ? "smooth" : "auto",
top: element ? element.offsetTop : 0
});
}, 100);
}, [location]);
return null;
};
ScrollHandler.propTypes = {
location: PropTypes.shape({
pathname: PropTypes.string,
search: PropTypes.string,
hash: PropTypes.string,
state: PropTypes.any,
key: PropTypes.string
}).isRequired
};
export default withRouter(ScrollHandler);
components/Navigation(更改 url 哈希历史记录位置的链接)
import React from "react";
import { Link } from "react-router-dom";
import List from "../List";
const Navigation = () => (
<List>
{[1, 2, 3, 4, 5].map(num => (
<li key={num}>
<Link to={`/#section${num}`}>Section {num}</Link>
</li>
))}
</List>
);
export default Navigation;
components/Sections(Headline
组件包含将匹配的 id
)
import React from "react";
import Headline from "../Headline";
const Sections = () =>
[1, 2, 3, 4, 5].map(num => (
<Headline key={num} id={`#section${num}`}>
Section {num}
</Headline>
));
export default Sections;
index.js
import React from "react";
import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Container from "./components/Container";
import Navigation from "./components/Navigation";
import Sections from "./components/Sections";
import ScrollHandler from "./components/ScrollHandler";
import "./styles.css";
const App = () => (
<BrowserRouter>
<Container>
<ScrollHandler />
<Navigation />
<Sections />
</Container>
</BrowserRouter>
);
render(<App />, document.getElementById("root"));