javascript 如何使用react进行带点的水平滚动

fumotvh3  于 2023-04-10  发布在  Java
关注(0)|答案(2)|浏览(191)

bounty还有6天到期。回答此问题可获得+50声望奖励。manish thakur正在寻找规范答案

我正在处理一个小部分,我必须水平显示一些divs,所以当它超出空间时,我使用css作为overflow-x:auto,以便它可以滚动。

我所做的

<div className="App d-flex">
  {data.map((li) => {
    return (
      <div key={li.id} className="boxes">
        {li.name}
      </div>
    );
  })}
</div>

下面是我的CSS

.d-flex {
  display: flex;
}
.boxes {
  padding: 12px;
  margin: 4px;
  background-color: rgb(196, 218, 243);
  min-width: 150px;
  overflow-x: auto;
  text-align: center;
  border-radius: 6px;
}

"我想做的事"

  • 我想把点在那里,以便当用户点击点它应该滚动。
  • 只有当超过项目的数量时,点才应该触发,这意味着如果在一个屏幕上可以显示的项目较少,则没有点,否则是点。
  • 在这里,我不知道如何使用react-hooks来做到这一点。

Here is my Code SandBox

a5g8bdjr

a5g8bdjr1#

先解决问题,然后编码。

解决方案

观察容器div、第一个框的div和最后一个框的div,并相应地更改UI。
保留布尔值(简单变量就可以了,不需要状态),通过与容器比较(是否粘滞)来检查左按钮和右按钮是否可见。

Code(idea)

使用ref获取DOM节点(而不是document.getElem...)。使用myRef.current.getBoundingClientRect()获取它们的位置和尺寸。
伪代码:

<div ref={containerRef}>
  {myArray.map((item, idx) => <div ref={idx === 0 firstBoxRef ? (idx === myArray.length - 1 ? lastBoxRef : null)}>...</div>}
</div>

当然,您需要添加按钮、overflowmax-width属性和onClick scroll
PS:ref的一个目的是作为document.getElementById的替代品。

5ssjco0h

5ssjco0h2#

App容器div的宽度设置为max-content,以允许该div溢出其父div。您可以从CSS中删除overflow-x: auto行,因为它没有做任何事情。该属性需要在溢出的容器上设置,在本例中是窗口。窗口默认显示水平滚动条。

.App {
  width: max-content;
}

使用Resive Observer API监听可滚动容器或App容器何时调整大小。在下面的示例中,我使用窗口作为可滚动容器,但我观察文档主体,因为您无法直接观察窗口。
然后就只需要比较App容器的宽度和可滚动容器的宽度了,你可以设置一个状态变量来决定是否显示圆点。

useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const observer = new ResizeObserver(() => {
      setOverflow(container.clientWidth > window.innerWidth);
    });

    observer.observe(container);
    observer.observe(document.body);

    // Cleanup
    return () => observer.disconnect();
  }, [containerRef.current]);

片段示例

let data = [
  {
    name: 'steve',
    id: 1,
  },
  {
    name: 'Matt',
    id: 2,
  },
  {
    name: 'michel',
    id: 3,
  },
  {
    name: 'Morgan',
    id: 4,
  },
  {
    name: 'joss',
    id: 5,
  },
  {
    name: 'stephen',
    id: 6,
  },
  {
    name: 'clark',
    id: 7,
  },
  {
    name: 'Simmons',
    id: 8,
  },
  {
    name: 'Chris',
    id: 9,
  },
  {
    name: 'Beven',
    id: 10,
  },
];

function App() {
  const containerRef = React.createRef();
  const [overflow, setOverflow] = React.useState(false);
  const [num, setNum] = React.useState(3);

  React.useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const observer = new ResizeObserver(() => {
      setOverflow(container.clientWidth > window.innerWidth);
    });

    observer.observe(container);
    observer.observe(document.body);

    // Cleanup
    return () => observer.disconnect();
  }, [containerRef.current]);

  function scrollRight() {
    window.scrollBy(window.innerWidth, 0);
  }
  
  function scrollLeft() {
    window.scrollBy(-window.innerWidth, 0);
  }

  function add() {
    setNum((num) => Math.min(num + 1, data.length));
  }

  function remove() {
    setNum((num) => Math.max(num - 1, 0));
  }

  return (
    <div>
      <div className="App d-flex" ref={containerRef}>
        {data.slice(0, num).map((li) => {
          return (
            <div key={li.id} className="boxes">
              {li.name}
            </div>
          );
        })}
      </div>
      <div className="arrow-container">
        {overflow && (
          <React.Fragment>
            <button className="left-arrow" onClick={scrollLeft}>
              {'<'}
            </button>
            <button className="right-arrow" onClick={scrollRight}>
              {'>'}
            </button>
          </React.Fragment>
        )}
      </div>
      <button onClick={add}>ADD</button>
      <br />
      <br />
      <button onClick={remove}>REMOVE</button>
    </div>
  );
}

const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(<App />);
.d-flex {
  display: flex;
}

.App {
  width: max-content;
}

.boxes {
  padding: 12px;
  margin: 4px;
  background-color: rgb(196, 218, 243);
  min-width: 150px;
  text-align: center;
  border-radius: 6px;
}

.arrow-container {
  height: 2em;
}

button {
  position: fixed;
}

.right-arrow {
  right: 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Stackblitz Typescript示例

https://stackblitz.com/edit/react-ts-kkpugp?file=App.tsx
我假设你想让window成为可滚动元素。如果你想让一个不同的父元素成为可滚动元素,那么将 *parent的 * overflow-x设置为auto,并观察它而不是文档正文。然后你可以将App容器的宽度与该父元素的宽度进行比较,而不是window。

相关问题