加载时如何滚动React页面?

Dan*_*cro 6 reactjs react-select

我想在URL(myapp.com#somevalue)中传递一个值作为哈希值,并在页面加载时让页面滚动到该项目-这正是自互联网开始以来使用哈希片段的行为。我尝试使用scrollIntoView,但在iOS上失败。然后,我尝试仅取消设置/设置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);
    }
  }
Run Code Online (Sandbox Code Playgroud)

编辑:我追踪了重新渲染页面的React行,因此在它已经滚动到我告诉它在componentDidMount()中的位置之后,重置了滚动位置。就是这个style[styleName] = styleValue;在重新渲染页面时,它正在设置反应选择框组件的输入框组件的width样式属性。堆栈跟踪就在它这样做之前

(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
Run Code Online (Sandbox Code Playgroud)

我不知道将指令滚动到何处。设置这些样式后必须发生,这是在componentDidMount()之后发生的。

编辑:我需要更好地明确说明我需要这样做。很抱歉以前没有这样做。

必须拥有

这必须在所有常见的台式机和移动设备上都有效。

页面加载时,可能会出现三种情况,具体取决于#后面的网址中提供的查询:

  • 1)没有提供查询-没有任何反应
  • 2)提供了有效的查询-页面立即滚动到所需的锚点,页面的标题更改为选项的标签
  • 3)提供了无效的查询-将查询输入到搜索框中,使搜索框处于焦点状态,并且菜单打开时,其选项受所提供的查询的限制,就好像键入了它们一样。光标位于搜索框中的查询的末尾,以便用户可以修改查询。

有效查询是与选项之一的值匹配的查询。无效查询就是无效查询。

浏览器的后退和前进按钮应相应地移动滚动位置。

每当从“搜索”框中选择一个选项时,页面应立即滚动到该锚点,查询应清除并返回到占位符“ Search ...”,URL应更新,并且文档标题应更改为该选项的标签。

可选,但会很棒

选择后,菜单关闭,查询返回到“搜索...”,或者

  • 搜索框将保留焦点,以便用户可以开始键入另一个查询。下次单击该菜单时,菜单将打开,并且将恢复选择之前的搜索框查询,菜单的过滤器和菜单滚动位置(首选),或者
  • 搜索框失去焦点。下次将其聚焦时,菜单将打开,并且将恢复(首选)菜单,菜单的过滤器和菜单滚动位置之前的搜索框查询,或者
  • 搜索框将保留焦点,以便用户可以开始键入另一个查询。先前的查询和菜单滚动位置将丢失。

Dan*_*cro 2

我将其放在组件文件中的导入之后:

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')
});
Run Code Online (Sandbox Code Playgroud)

并为我准备这个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
  }
Run Code Online (Sandbox Code Playgroud)