如何在加载时滚动 React 页面?
How to scroll a React page when it loads?
我想在 url (myapp.com#somevalue) 中传递一个值作为散列,并在页面加载时让页面滚动到该项目 - 正是使用散列的行为自互联网诞生以来的片段。我尝试使用 scrollIntoView 但在 iOS 上失败了。然后我只尝试 unsetting/setting window.location.hash 但似乎存在竞争条件。延迟大于600ms才有效
我想要一个更可靠的解决方案,不想引入不必要的延迟。当延迟太短时,它似乎滚动到所需的项目,但随后滚动到页面顶部。您不会看到此演示的效果,但它发生在我的实际应用程序 https://codesandbox.io/s/pjok544nrx 第 75 行
componentDidMount() {
let self = this;
let updateSearchControl = hash => {
let selectedOption = self.state.searchOptions.filter(
option => option.value === hash
)[0];
if (selectedOption) {
// this doesn't work with Safari on iOS
// document.getElementById(hash).scrollIntoView(true);
// this works if delay is 900 but not 500 ms
setTimeout(() => {
// unset and set the hash to trigger scrolling to target
window.location.hash = null;
window.location.hash = hash;
// scroll back by the height of the Search box
window.scrollBy(
0,
-document.getElementsByClassName("heading")[0].clientHeight
);
}, 900);
} else if (hash) {
this.searchRef.current.select.focus();
}
};
// Get the hash
// I want this to work as a Google Apps Script too which runs in
// an iframe and has a special way to get the hash
if (!!window["google"]) {
let updateHash = location => {
updateSearchControl(location.hash);
};
eval("google.script.url.getLocation(updateHash)");
} else {
let hash = window.location.hash.slice(1);
updateSearchControl(hash);
}
}
编辑:我追踪到 re-renders 页面的 React 行,因此在它已经滚动到我告诉它进入 componentDidMount() 的位置后重置滚动位置。是 this one。
style[styleName] = styleValue;
在页面 re-rendered 时,它正在设置 react-select 框组件的输入框组件的宽度样式 属性。执行此操作之前的堆栈跟踪看起来像
(anonymous) @ VM38319:1
setValueForStyles @ react-dom.development.js:6426
updateDOMProperties @ react-dom.development.js:7587
updateProperties @ react-dom.development.js:7953
commitUpdate @ react-dom.development.js:8797
commitWork @ react-dom.development.js:17915
commitAllHostEffects @ react-dom.development.js:18634
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
commitRoot @ react-dom.development.js:18867
(anonymous) @ react-dom.development.js:20372
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:20371
performWorkOnRoot @ react-dom.development.js:20300
performWork @ react-dom.development.js:20208
performSyncWork @ react-dom.development.js:20182
requestWork @ react-dom.development.js:20051
scheduleWork @ react-dom.development.js:19865
scheduleRootUpdate @ react-dom.development.js:20526
updateContainerAtExpirationTime @ react-dom.development.js:20554
updateContainer @ react-dom.development.js:20611
ReactRoot.render @ react-dom.development.js:20907
(anonymous) @ react-dom.development.js:21044
unbatchedUpdates @ react-dom.development.js:20413
legacyRenderSubtreeIntoContainer @ react-dom.development.js:21040
render @ react-dom.development.js:21109
(anonymous) @ questionsPageIndex.jsx:10
./src/client/questionsPageIndex.jsx @ index.html:673
__webpack_require__ @ index.html:32
(anonymous) @ index.html:96
(anonymous) @ index.html:99
我不知道将滚动页面的指令移到哪里。它必须在设置这些样式之后发生,这发生在 componentDidMount() 之后。
编辑:我需要更好地明确我需要这样做的目的。抱歉之前没有这样做。
必备
这必须适用于所有常见的桌面和移动设备。
当页面加载时,可能会出现三种情况,具体取决于在 #:
之后 url 中提供的查询
- 1) 未提供任何查询 - 没有任何反应
- 2) 提供了有效的查询 - 页面立即滚动到所需的锚点并且页面的标题更改为选项的标签
- 3) 提供了无效的查询 - 将查询输入到搜索框中,搜索框被聚焦,菜单打开时选项受提供的查询限制,就好像它们是输入的一样。光标位于在查询末尾的搜索框中,以便用户可以修改查询。
有效的查询是指匹配其中一个选项的值的查询。无效查询是指不存在的查询。
浏览器的后退和前进按钮应相应地移动滚动位置。
只要从搜索框中选择一个选项,页面就会立即滚动到该锚点,查询应该清除并返回到占位符 "Search...",url 应该更新,文档的标题应更改为选项的标签。
可选,但会很棒
选择后,菜单关闭,查询返回 "Search...",
- 搜索框保留焦点,因此用户可以开始输入另一个查询。下次点击,菜单打开,选择前的Searchbox查询,恢复菜单的过滤器和菜单滚动位置(最优选),或者
- 搜索框失去焦点。下次focused,菜单打开,选择前的Search box query,恢复菜单的filter和menu scroll position(首选),或者
- 搜索框保留焦点,因此用户可以开始输入另一个查询。先前的查询和菜单滚动位置丢失。
您可以使用 https://www.npmjs.com/package/element.scrollintoviewifneeded-polyfill.
尽快在您的应用程序中导入库
import 'element.scrollintoviewifneeded-polyfill';
您可以在所有 dom 节点上使用方法 scrollIntoViewIfNeeded();
。
该库将填充该方法,以便您可以在所有浏览器上使用它。
我建议您将它与 react ref
一起使用,这样您就不必调用 getElementById 或其他文档方法来检索 dom 节点。
const ref = React.createRef();
<div id="somevalue" ref={ref} />
在您的 componentDidMount
中,您可以使用描述的相同方法来检索要滚动的 div 的 ID,获取关联的 ref 并调用
ref.current.scrollIntoViewIfNeeded();
如果 ref 是正确的 div 引用,您显然可以将所有 ref 存储在一个映射中,而不是在您的组件方法中检索。
使用 react-scrollable-anchor
库可能更容易做到这一点:
import React from "react";
import ReactDOM from "react-dom";
import ScrollableAnchor from "react-scrollable-anchor";
class App extends React.Component {
render() {
return (
<React.Fragment>
<div style={{ marginBottom: 7000 }}>nothing to see here</div>
<div style={{ marginBottom: 7000 }}>never mind me</div>
<ScrollableAnchor id={"doge"}>
<div>bork</div>
</ScrollableAnchor>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
你可以通过这里看到它的工作:https://zwoj0xw503.codesandbox.io/#doge
您可以通过使用 react-router-dom
的 HashRouter 和 React 的 ref.current.scrollIntoView()
或 window.scrollTo(ref.currrent.offsetTop)
来简化您的代码。
目前正在 Chrome (desktop/android)、Firefox(桌面)、Silk Browser(android)、Saumsung Internet(android)和 Safari 上进行测试和工作(iOS -- 需要注意的是它会立即跳转到所选内容)。虽然我能够测试并确认它在沙箱环境的 iframe
中工作,但您必须 adapt/test 它在独立的 iframe
.
中
我还想指出您的方法非常 jQuery
并且您应该避免直接尝试利用或操纵 DOM
and/or window
.此外,您似乎在整个代码中使用了很多 let
变量,但它们保持不变。相反,它们应该是一个 const
变量,因为 React 每次重新渲染时都会评估变量,因此除非您计划在重新渲染过程中更改该变量,否则无需使用 let
。
工作示例:https://v6y5211n4l.codesandbox.io
components/ScrollBar
import React, { Component } from "react";
import PropTypes from "prop-types";
import Helmet from "react-helmet";
import Select from "react-select";
import { withRouter } from "react-router-dom";
import "./styles.css";
const scrollOpts = {
behavior: "smooth",
block: "start"
};
class ScrollBar extends Component {
constructor(props) {
super(props);
const titleRefs = props.searchOptions.map(
({ label }) => (this[label] = React.createRef())
); // map over options and use "label" as a ref name; ex: this.orange
this.topWindow = React.createRef();
this.searchRef = React.createRef();
const pathname = props.history.location.pathname.replace(/\//g, ""); // set current pathname without the "/"
this.state = {
titleRefs,
menuIsOpen: false,
isValid: props.searchOptions.some(({ label }) => label === pathname), // check if the current pathname matches any of the labels
pathname
};
}
componentDidMount() {
const { pathname, isValid } = this.state;
if (isValid) this.scrollToElement(); // if theres a pathname and it matches a label, scroll to it
if (!isValid && pathname) this.searchRef.current.select.focus(); // if there's a pathname but it's invalid, focus on the search bar
}
// allows us to update state based upon prop updates (in this case
// we're looking for changes in the history.location.pathname)
static getDerivedStateFromProps(props, state) {
const nextPath = props.history.location.pathname.replace(/\//g, "");
const isValid = props.searchOptions.some(({ label }) => label === nextPath);
return state.pathname !== nextPath ? { pathname: nextPath, isValid } : null; // if the path has changed, update the pathname and whether or not it is valid
}
// allows us to compare new state to old state (in this case
// we're looking for changes in the pathname)
componentDidUpdate(prevProps, prevState) {
if (this.state.pathname !== prevState.pathname) {
this.scrollToElement();
}
}
scrollToElement = () => {
const { isValid, pathname } = this.state;
const elem = isValid ? pathname : "topWindow";
setTimeout(() => {
window.scrollTo({
behavior: "smooth",
top: this[elem].current.offsetTop - 45
});
}, 100);
};
onInputChange = (options, { action }) => {
if (action === "menu-close") {
this.setState({ menuIsOpen: false }, () =>
this.searchRef.current.select.blur()
);
} else {
this.setState({ menuIsOpen: true });
}
};
onChange = ({ value }) => {
const { history } = this.props;
if (history.location.pathname.replace(/\//g, "") !== value) { // if the select value is different than the previous selected value, update the url -- required, otherwise, react-router will complain about pushing the same pathname/value that is current in the url
history.push(value);
}
this.searchRef.current.select.blur();
};
onFocus = () => this.setState({ menuIsOpen: true });
render() {
const { pathname, menuIsOpen, titleRefs } = this.state;
const { searchOptions, styles } = this.props;
return (
<div className="container">
<Helmet title={this.state.pathname || "Select an option"} />
<div className="heading">
<Select
placeholder="Search..."
isClearable={true}
isSearchable={true}
options={searchOptions}
defaultInputValue={pathname}
onFocus={this.onFocus}
onInputChange={this.onInputChange}
onChange={this.onChange}
menuIsOpen={menuIsOpen}
ref={this.searchRef}
value={null}
styles={styles || {}}
/>
</div>
<div className="fruits-list">
<div ref={this.topWindow} />
{searchOptions.map(({ label, value }, key) => (
<div key={value} id={value}>
<p ref={titleRefs[key]}>{label}</p>
{[1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14].map(num => (
<p key={num}>{num}</p>
))}
</div>
))}
</div>
</div>
);
}
}
ScrollBar.propTypes = {
searchOptions: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired
}).isRequired
).isRequired,
styles: PropTypes.objectOf(PropTypes.func)
};
export default withRouter(ScrollBar);
index.js
import React from "react";
import { render } from "react-dom";
import { HashRouter } from "react-router-dom";
import Helmet from "react-helmet";
import ScrollBar from "../src/components/ScrollBar";
const config = {
htmlAttributes: { lang: "en" },
title: "My App",
titleTemplate: "Scroll Search - %s",
meta: [
{
name: "description",
content: "The best app in the world."
}
]
};
const searchOptions = [
{
label: "apple",
value: "apple"
},
{
label: "orange",
value: "orange"
},
{
label: "banana",
value: "banana"
},
{
label: "strawberry",
value: "strawberry"
}
];
const styles = {
menu: base => ({ ...base, width: "100%", height: "75vh" }),
menuList: base => ({ ...base, minHeight: "75vh" }),
option: base => ({ ...base, color: "blue" })
};
const App = () => (
<HashRouter>
<Helmet {...config} />
<ScrollBar searchOptions={searchOptions} styles={styles} />
</HashRouter>
);
render(<App />, document.getElementById("root"));
我把它放在组件文件中导入之后:
let initialValidSlug = '';
window.addEventListener('load', () => {
window.location.hash = '';
window.location.hash = (initialValidSlug ? initialValidSlug : '');
window.scrollBy(0, -document.getElementsByClassName("heading")[0].clientHeight);
console.log('window.addEventListener')
});
给我的 componentDidMount()
:
componentDidMount() {
const { pathname, isValid } = this.state;
if(!isValid && pathname) { // if there's a pathname but it's invalid,
this.searchRef.current.select.focus(); // focus on the search bar
}
initialValidSlug = pathname; // sets the value to be used in the $.ready() above
}
我想在 url (myapp.com#somevalue) 中传递一个值作为散列,并在页面加载时让页面滚动到该项目 - 正是使用散列的行为自互联网诞生以来的片段。我尝试使用 scrollIntoView 但在 iOS 上失败了。然后我只尝试 unsetting/setting window.location.hash 但似乎存在竞争条件。延迟大于600ms才有效
我想要一个更可靠的解决方案,不想引入不必要的延迟。当延迟太短时,它似乎滚动到所需的项目,但随后滚动到页面顶部。您不会看到此演示的效果,但它发生在我的实际应用程序 https://codesandbox.io/s/pjok544nrx 第 75 行
componentDidMount() {
let self = this;
let updateSearchControl = hash => {
let selectedOption = self.state.searchOptions.filter(
option => option.value === hash
)[0];
if (selectedOption) {
// this doesn't work with Safari on iOS
// document.getElementById(hash).scrollIntoView(true);
// this works if delay is 900 but not 500 ms
setTimeout(() => {
// unset and set the hash to trigger scrolling to target
window.location.hash = null;
window.location.hash = hash;
// scroll back by the height of the Search box
window.scrollBy(
0,
-document.getElementsByClassName("heading")[0].clientHeight
);
}, 900);
} else if (hash) {
this.searchRef.current.select.focus();
}
};
// Get the hash
// I want this to work as a Google Apps Script too which runs in
// an iframe and has a special way to get the hash
if (!!window["google"]) {
let updateHash = location => {
updateSearchControl(location.hash);
};
eval("google.script.url.getLocation(updateHash)");
} else {
let hash = window.location.hash.slice(1);
updateSearchControl(hash);
}
}
编辑:我追踪到 re-renders 页面的 React 行,因此在它已经滚动到我告诉它进入 componentDidMount() 的位置后重置滚动位置。是 this one。
style[styleName] = styleValue;
在页面 re-rendered 时,它正在设置 react-select 框组件的输入框组件的宽度样式 属性。执行此操作之前的堆栈跟踪看起来像
(anonymous) @ VM38319:1
setValueForStyles @ react-dom.development.js:6426
updateDOMProperties @ react-dom.development.js:7587
updateProperties @ react-dom.development.js:7953
commitUpdate @ react-dom.development.js:8797
commitWork @ react-dom.development.js:17915
commitAllHostEffects @ react-dom.development.js:18634
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
commitRoot @ react-dom.development.js:18867
(anonymous) @ react-dom.development.js:20372
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:20371
performWorkOnRoot @ react-dom.development.js:20300
performWork @ react-dom.development.js:20208
performSyncWork @ react-dom.development.js:20182
requestWork @ react-dom.development.js:20051
scheduleWork @ react-dom.development.js:19865
scheduleRootUpdate @ react-dom.development.js:20526
updateContainerAtExpirationTime @ react-dom.development.js:20554
updateContainer @ react-dom.development.js:20611
ReactRoot.render @ react-dom.development.js:20907
(anonymous) @ react-dom.development.js:21044
unbatchedUpdates @ react-dom.development.js:20413
legacyRenderSubtreeIntoContainer @ react-dom.development.js:21040
render @ react-dom.development.js:21109
(anonymous) @ questionsPageIndex.jsx:10
./src/client/questionsPageIndex.jsx @ index.html:673
__webpack_require__ @ index.html:32
(anonymous) @ index.html:96
(anonymous) @ index.html:99
我不知道将滚动页面的指令移到哪里。它必须在设置这些样式之后发生,这发生在 componentDidMount() 之后。
编辑:我需要更好地明确我需要这样做的目的。抱歉之前没有这样做。
必备
这必须适用于所有常见的桌面和移动设备。
当页面加载时,可能会出现三种情况,具体取决于在 #:
之后 url 中提供的查询- 1) 未提供任何查询 - 没有任何反应
- 2) 提供了有效的查询 - 页面立即滚动到所需的锚点并且页面的标题更改为选项的标签
- 3) 提供了无效的查询 - 将查询输入到搜索框中,搜索框被聚焦,菜单打开时选项受提供的查询限制,就好像它们是输入的一样。光标位于在查询末尾的搜索框中,以便用户可以修改查询。
有效的查询是指匹配其中一个选项的值的查询。无效查询是指不存在的查询。
浏览器的后退和前进按钮应相应地移动滚动位置。
只要从搜索框中选择一个选项,页面就会立即滚动到该锚点,查询应该清除并返回到占位符 "Search...",url 应该更新,文档的标题应更改为选项的标签。
可选,但会很棒
选择后,菜单关闭,查询返回 "Search...",
- 搜索框保留焦点,因此用户可以开始输入另一个查询。下次点击,菜单打开,选择前的Searchbox查询,恢复菜单的过滤器和菜单滚动位置(最优选),或者
- 搜索框失去焦点。下次focused,菜单打开,选择前的Search box query,恢复菜单的filter和menu scroll position(首选),或者
- 搜索框保留焦点,因此用户可以开始输入另一个查询。先前的查询和菜单滚动位置丢失。
您可以使用 https://www.npmjs.com/package/element.scrollintoviewifneeded-polyfill.
尽快在您的应用程序中导入库
import 'element.scrollintoviewifneeded-polyfill';
您可以在所有 dom 节点上使用方法 scrollIntoViewIfNeeded();
。
该库将填充该方法,以便您可以在所有浏览器上使用它。
我建议您将它与 react ref
一起使用,这样您就不必调用 getElementById 或其他文档方法来检索 dom 节点。
const ref = React.createRef();
<div id="somevalue" ref={ref} />
在您的 componentDidMount
中,您可以使用描述的相同方法来检索要滚动的 div 的 ID,获取关联的 ref 并调用
ref.current.scrollIntoViewIfNeeded();
如果 ref 是正确的 div 引用,您显然可以将所有 ref 存储在一个映射中,而不是在您的组件方法中检索。
使用 react-scrollable-anchor
库可能更容易做到这一点:
import React from "react";
import ReactDOM from "react-dom";
import ScrollableAnchor from "react-scrollable-anchor";
class App extends React.Component {
render() {
return (
<React.Fragment>
<div style={{ marginBottom: 7000 }}>nothing to see here</div>
<div style={{ marginBottom: 7000 }}>never mind me</div>
<ScrollableAnchor id={"doge"}>
<div>bork</div>
</ScrollableAnchor>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
你可以通过这里看到它的工作:https://zwoj0xw503.codesandbox.io/#doge
您可以通过使用 react-router-dom
的 HashRouter 和 React 的 ref.current.scrollIntoView()
或 window.scrollTo(ref.currrent.offsetTop)
来简化您的代码。
目前正在 Chrome (desktop/android)、Firefox(桌面)、Silk Browser(android)、Saumsung Internet(android)和 Safari 上进行测试和工作(iOS -- 需要注意的是它会立即跳转到所选内容)。虽然我能够测试并确认它在沙箱环境的 iframe
中工作,但您必须 adapt/test 它在独立的 iframe
.
我还想指出您的方法非常 jQuery
并且您应该避免直接尝试利用或操纵 DOM
and/or window
.此外,您似乎在整个代码中使用了很多 let
变量,但它们保持不变。相反,它们应该是一个 const
变量,因为 React 每次重新渲染时都会评估变量,因此除非您计划在重新渲染过程中更改该变量,否则无需使用 let
。
工作示例:https://v6y5211n4l.codesandbox.io
components/ScrollBar
import React, { Component } from "react";
import PropTypes from "prop-types";
import Helmet from "react-helmet";
import Select from "react-select";
import { withRouter } from "react-router-dom";
import "./styles.css";
const scrollOpts = {
behavior: "smooth",
block: "start"
};
class ScrollBar extends Component {
constructor(props) {
super(props);
const titleRefs = props.searchOptions.map(
({ label }) => (this[label] = React.createRef())
); // map over options and use "label" as a ref name; ex: this.orange
this.topWindow = React.createRef();
this.searchRef = React.createRef();
const pathname = props.history.location.pathname.replace(/\//g, ""); // set current pathname without the "/"
this.state = {
titleRefs,
menuIsOpen: false,
isValid: props.searchOptions.some(({ label }) => label === pathname), // check if the current pathname matches any of the labels
pathname
};
}
componentDidMount() {
const { pathname, isValid } = this.state;
if (isValid) this.scrollToElement(); // if theres a pathname and it matches a label, scroll to it
if (!isValid && pathname) this.searchRef.current.select.focus(); // if there's a pathname but it's invalid, focus on the search bar
}
// allows us to update state based upon prop updates (in this case
// we're looking for changes in the history.location.pathname)
static getDerivedStateFromProps(props, state) {
const nextPath = props.history.location.pathname.replace(/\//g, "");
const isValid = props.searchOptions.some(({ label }) => label === nextPath);
return state.pathname !== nextPath ? { pathname: nextPath, isValid } : null; // if the path has changed, update the pathname and whether or not it is valid
}
// allows us to compare new state to old state (in this case
// we're looking for changes in the pathname)
componentDidUpdate(prevProps, prevState) {
if (this.state.pathname !== prevState.pathname) {
this.scrollToElement();
}
}
scrollToElement = () => {
const { isValid, pathname } = this.state;
const elem = isValid ? pathname : "topWindow";
setTimeout(() => {
window.scrollTo({
behavior: "smooth",
top: this[elem].current.offsetTop - 45
});
}, 100);
};
onInputChange = (options, { action }) => {
if (action === "menu-close") {
this.setState({ menuIsOpen: false }, () =>
this.searchRef.current.select.blur()
);
} else {
this.setState({ menuIsOpen: true });
}
};
onChange = ({ value }) => {
const { history } = this.props;
if (history.location.pathname.replace(/\//g, "") !== value) { // if the select value is different than the previous selected value, update the url -- required, otherwise, react-router will complain about pushing the same pathname/value that is current in the url
history.push(value);
}
this.searchRef.current.select.blur();
};
onFocus = () => this.setState({ menuIsOpen: true });
render() {
const { pathname, menuIsOpen, titleRefs } = this.state;
const { searchOptions, styles } = this.props;
return (
<div className="container">
<Helmet title={this.state.pathname || "Select an option"} />
<div className="heading">
<Select
placeholder="Search..."
isClearable={true}
isSearchable={true}
options={searchOptions}
defaultInputValue={pathname}
onFocus={this.onFocus}
onInputChange={this.onInputChange}
onChange={this.onChange}
menuIsOpen={menuIsOpen}
ref={this.searchRef}
value={null}
styles={styles || {}}
/>
</div>
<div className="fruits-list">
<div ref={this.topWindow} />
{searchOptions.map(({ label, value }, key) => (
<div key={value} id={value}>
<p ref={titleRefs[key]}>{label}</p>
{[1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14].map(num => (
<p key={num}>{num}</p>
))}
</div>
))}
</div>
</div>
);
}
}
ScrollBar.propTypes = {
searchOptions: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired
}).isRequired
).isRequired,
styles: PropTypes.objectOf(PropTypes.func)
};
export default withRouter(ScrollBar);
index.js
import React from "react";
import { render } from "react-dom";
import { HashRouter } from "react-router-dom";
import Helmet from "react-helmet";
import ScrollBar from "../src/components/ScrollBar";
const config = {
htmlAttributes: { lang: "en" },
title: "My App",
titleTemplate: "Scroll Search - %s",
meta: [
{
name: "description",
content: "The best app in the world."
}
]
};
const searchOptions = [
{
label: "apple",
value: "apple"
},
{
label: "orange",
value: "orange"
},
{
label: "banana",
value: "banana"
},
{
label: "strawberry",
value: "strawberry"
}
];
const styles = {
menu: base => ({ ...base, width: "100%", height: "75vh" }),
menuList: base => ({ ...base, minHeight: "75vh" }),
option: base => ({ ...base, color: "blue" })
};
const App = () => (
<HashRouter>
<Helmet {...config} />
<ScrollBar searchOptions={searchOptions} styles={styles} />
</HashRouter>
);
render(<App />, document.getElementById("root"));
我把它放在组件文件中导入之后:
let initialValidSlug = '';
window.addEventListener('load', () => {
window.location.hash = '';
window.location.hash = (initialValidSlug ? initialValidSlug : '');
window.scrollBy(0, -document.getElementsByClassName("heading")[0].clientHeight);
console.log('window.addEventListener')
});
给我的 componentDidMount()
:
componentDidMount() {
const { pathname, isValid } = this.state;
if(!isValid && pathname) { // if there's a pathname but it's invalid,
this.searchRef.current.select.focus(); // focus on the search bar
}
initialValidSlug = pathname; // sets the value to be used in the $.ready() above
}