【问题标题】:How to implement a scrollspy with React如何使用 React 实现滚动间谍
【发布时间】:2018-08-04 14:55:32
【问题描述】:

我想实现一个没有引导程序的 scrollspy

网上查了很多代码,都是用jQuery实现的。

如何实现scrollspy只用React的强大功能?

【问题讨论】:

    标签: javascript reactjs scrollspy


    【解决方案1】:

    我制作了一个 React Wrapper(与 Render-Props 一起使用):

    Live Codepen Example


    const {useState, useEffect, useCallback, useRef} = React;
    
    /**
     *
     * @param {Object} scrollParent [DOM node of scrollable element]
     * @param {Array} _targetElements [Array of nodes to spy on]
     */
    const spyScroll = (scrollParent, _targetElements) => {
      if (!scrollParent) return false;
    
      // create an Object with all children that has data-name attribute
      const targetElements =
        _targetElements ||
        [...scrollParent.children].reduce(
          (map, item) =>
            item.dataset.name ? { [item.dataset.name]: item, ...map } : map,
          {}
        );
    
      let bestMatch = {};
    
      for (const sectionName in targetElements) {
        if (Object.prototype.hasOwnProperty.call(targetElements, sectionName)) {
          const domElm = targetElements[sectionName];
          const delta = Math.abs(scrollParent.scrollTop - domElm.offsetTop); // check distance from top, takig scroll into account
    
          if (!bestMatch.sectionName) 
            bestMatch = { sectionName, delta };
    
          // check which delet is closest to "0"
          if (delta < bestMatch.delta) {
            bestMatch = { sectionName, delta };
          }
        }
      }
    
      // update state with best-fit section
      return bestMatch.sectionName;
    };
    
    
    
    
    /**
     * Given a parent element ref, this render-props function returns
     * which of the parent's sections is currently scrolled into view
     * @param {Object} sectionsWrapperRef [Scrollable parent node React ref Object]
     */
    const CurrentScrolledSection = ({ sectionsWrapperRef, children }) => {
      const [currentSection, setCurrentSection] = useState();
    
      // adding the scroll event listener inside this component, and NOT the parent component, to prever re-rendering of the parent component when
      // the scroll listener is fired and the state is updated, which causes noticable lag.
      useEffect(() => {
        const wrapperElm = sectionsWrapperRef.current;
        if (wrapperElm) {
          wrapperElm.addEventListener('scroll', e => setCurrentSection(spyScroll(e.target)));
          setCurrentSection(spyScroll(wrapperElm));
        }
    
        // unbind
        return () => wrapperElm.removeEventListener('scroll', throttledOnScroll)
      }, []);
    
      return children({ currentSection });
    };
    
    function App(){
      const sectionsWrapperRef = useRef()
      return <CurrentScrolledSection sectionsWrapperRef={sectionsWrapperRef}>
        {({ currentSection }) => <div ref={sectionsWrapperRef}>
        <section 
          data-name="section-a" 
          className={currentSection === "section-a" ? 'active' : ''}
        >Section A</section>
        <section 
          data-name="section-b" 
          className={currentSection === "section-b" ? 'active' : ''}
        >Section B</section>
        <section 
          data-name="section-c" 
          className={currentSection === "section-c" ? 'active' : ''}
        >Section C</section>
        </div>
      }
      </CurrentScrolledSection>
    }
    
    
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    )
    html, body, #root{ height: 95%; overflow:hidden; }
    
    #root > div{ 
      padding-bottom:20em; 
      height: 100%; 
      overflow:auto; 
      box-sizing: border-box;
    }
    
    section{ 
      height: 50vh;
      border-bottom: 1px solid red;
    }
    
    section.active{ background:lightyellow; }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>
    <div id='root'></div>

    这并不完美,因为滚动方向确实很重要,因为它暗示了用户的意图。

    【讨论】:

    • 你能帮我把它改成顶部栏菜单吗?我只需要更改 Aside 的 css 吗?
    【解决方案2】:

    现场运行演示

    https://codesandbox.io/s/gallant-wing-ue2ks

    步骤

    1。添加依赖

    使用 npm

    npm i react-scrollspy
    

    或使用纱线

    yarn add react-scrollspy
    

    2。创建您的 HTML 部分

    <section id="section-1">
        <!-- Content goes here -->
    </section>
    <section id="section-2">
        <!-- Content goes here -->
    </section>
    
    <!-- .... -->
    
    <section id="section-n">
        <!-- Content goes here -->
    </section>
    

    3。将这些部分的 ID 添加到 Scrollspy items

    <Scrollspy items={ ['section-1', 'section-2', ..., 'section-n'] } />
    

    4。添加一些样式

    查看此文档https://makotot.github.io/react-scrollspy/#section-3

    【讨论】:

      【解决方案3】:

      查看react-ui-scrollspy,非常好用。

      完全披露:我维护这个包。

      1. 在您的导航组件中
      <div>
        <p data-to-scrollspy-id="first">Section 1</p>
        <p data-to-scrollspy-id="second">Section 2</p>
      </div>
      
      1. 将要监视的元素包装在 &lt;ScrollSpy&gt; 组件中。
      import ScrollSpy from "react-ui-scrollspy";
      
      <ScrollSpy>
        <div id="first">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Aut dolores
          veritatis doloremque fugit. Soluta aperiam atque inventore deleniti,
          voluptatibus non fuga eos magni natus vel, rerum excepturi expedita.
          Tempore, vero!
        </div>
        <div id="second">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Aut dolores
          veritatis doloremque fugit. Soluta aperiam atque inventore deleniti,
          voluptatibus non fuga eos magni natus vel, rerum excepturi expedita.
          Tempore, vero!
        </div>
      </ScrollSpy>
      
      1. index.css 中处于活动状态的导航元素编写样式
      .active-scroll-spy {
        background-color: yellowgreen;
        border-radius: 15px;
      }
      

      【讨论】:

        【解决方案4】:

        您可以使用React-scrollspy。访问这个 git repo React-scrollspy

        【讨论】:

          【解决方案5】:

          尝试使用“react-scrollspy-nav”的 npm 并遵循其文档。 link

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-02-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多