css 如何使用React禁用div的滚动

u3r8eeie  于 2023-08-09  发布在  React
关注(0)|答案(2)|浏览(188)

我有一个移动的侧边栏,当它显示时,它从屏幕左侧占用300px。我检查它是否显示一个名为isOpen的变量。

<Navbar isOpen={isOpen} setIsOpen={setIsOpen} />
<div className={isOpen ? "content behind" : "content"}>
//content
</div>

字符串
侧边栏处于活动状态时,如何禁用导航栏div的点击和滚动?

.content.behind{
   pointer-events: none;
}


我试着使用这个,但滚动仍然是可能的。

.content.behind{
   overflow: hidden;
}


我也试过这样做,但是当显示侧边栏时,会显示内容部分的顶部,因为溢出是隐藏的。
我也在github上找到了这个自定义钩子。useScrollBlock它的工作,但当我使用它,scrollable是禁用的整个身体。应该可以滚动到侧边栏。

o4tp2gmn

o4tp2gmn1#

我假设.contant是可滚动元素(而不是整个主体)。在这种情况下,在下面的示例中同时使用pointer-events: noneoverflow: hidden似乎可以很好地工作。
你可以向下滚动,打开侧边栏,列表的滚动位置不会改变。但是,当滚动条隐藏时,您会注意到列表会水平移动(至少在Windows上,滚动条不是像macOS/iOS中那样的覆盖):

const sidebar = document.getElementById('sidebar')
const content = document.getElementById('content')
const toggleButton = document.getElementById('toggleButton')

toggleButton.addEventListener('click', () => {
  sidebar.classList.toggle('open')
  content.classList.toggle('behind')
  toggleButton.textContent = toggleButton.textContent === '👉' ? '👈' : '👉'
})
body {
  margin: 0;
}

#sidebar {
  position: fixed;
  top: 0;
  left: 0;
  width: 300px;
  height: 100vh;  
  background: black;
  transform: translate(-300px, 0);
  transition: transform linear 300ms;
  z-index: 1;
}

#sidebar.open {;
  transform: translate(0, 0);
}

#content {
  max-height: 100vh;
  overflow-y: scroll;
  padding: 8px;
  box-sizing: border-box;
}

#content.behind {
  opacity: 0.5;
  pointer-events: none;
  overflow: hidden;
}

#content > p {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100px;
  margin: 0;
  background: cyan;
  font-family: monospace;
  font-size: 32px;
}

#content > p + p {
  margin: 8px 0 0;
}

#content > p:hover {
  background: yellow;
}

#toggleButton {
  position: fixed;
  top: 8px;
  left: 8px;
  width: 40px;
  height: 40px;  
  background: white;
  border: 3px solid black;
  z-index: 2;
}
<div id="sidebar">
</div>

<div id="content">
  <p>0</p>
  <p>1</p>
  <p>2</p>
  <p>3</p>
  <p>4</p>
  <p>5</p>
  <p>6</p>
  <p>7</p>
  <p>8</p>
  <p>9</p>
</div>

<button id="toggleButton">👉</button>

在任何情况下,您的问题可能是特定于设备的,或者它取决于您的整体HTML结构。你可以在#content上添加一个覆盖层,这将阻止用户滚动它或与它的内容交互:

const sidebar = document.getElementById('sidebar')
const overlay = document.getElementById('overlay')
const toggleButton = document.getElementById('toggleButton')

toggleButton.addEventListener('click', () => {
  sidebar.classList.toggle('open')
  overlay.classList.toggle('visible')
  toggleButton.textContent = toggleButton.textContent === '👉' ? '👈' : '👉'
})
body {
  margin: 0;
}

#sidebar {
  position: fixed;
  top: 0;
  left: 0;
  width: 300px;
  height: 100vh;  
  background: black;
  transform: translate(-300px, 0);
  transition: transform linear 300ms;
  z-index: 1;
}

#sidebar.open {;
  transform: translate(0, 0);
}

#overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: white;
  opacity: 0;
  transition: opacity linear 300ms;
  pointer-events: none;
}

#overlay.visible {
  opacity: 0.5;
  pointer-events: auto;
}

#content {
  max-height: 100vh;
  overflow-y: scroll;
  padding: 8px;
  box-sizing: border-box;
}

#content > p {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100px;
  margin: 0;
  background: cyan;
  font-family: monospace;
  font-size: 32px;
}

#content > p + p {
  margin: 8px 0 0;
}

#content > p:hover {
  background: yellow;
}

#toggleButton {
  position: fixed;
  top: 8px;
  left: 8px;
  width: 40px;
  height: 40px;  
  background: white;
  border: 3px solid black;
  z-index: 2;
}
<div id="sidebar">
</div>

<div id="overlay">
</div>

<div id="content">
  <p>0</p>
  <p>1</p>
  <p>2</p>
  <p>3</p>
  <p>4</p>
  <p>5</p>
  <p>6</p>
  <p>7</p>
  <p>8</p>
  <p>9</p>
</div>

<button id="toggleButton">👉</button>
6qqygrtg

6qqygrtg2#

为了防止与页面的主要内容进行任何交互,通常要做的是创建一个div,放置在内容的顶部(但低于模态/侧边栏):

{isOpen ? <div className="modaloverlay"/> : ''}

字符串
然后在CSS中用一个z-index来定义它,它大于主内容中的所有内容,但低于模态中使用的内容(我的模态有z-index: 1000):

.modaloverlay{
  position:fixed;
  top:0;left:0;width:100vw;height:100vh;
  background-color:black;
  opacity:0.5;
  z-index: 999;
}


至于隐藏滚动条,这取决于页面设计的其他部分(您还没有分享),但overflow的隐藏通常需要在body元素处。它可以通过CSS类来完成,但我通过useEffect来完成:

useEffect(() => {
  if (isOpen) {
    document.body.style.overflow = 'hidden';
  }
  return () => {
    document.body.style.overflow = null;
  };
}, [isOpen]);


你可以在下面的代码片段中找到一个工作示例:

const Navbar = ({ isOpen, setIsOpen }) => {
  const buttonText = isOpen ? "Close" : "Open";
  const onClick = () => setIsOpen(!isOpen);
  return (
    <div className="navbar">
      {isOpen
        ? (<div>
            <p>Text on <b>OPENED</b> NavBar</p>
            <p>Extra text on NavBar...</p>
            <p>More extra text on NavBar!</p>
          </div>)
        : (<div>NavBar is Closed</div>)}
      <div><button onClick={onClick}>{buttonText}</button></div>
    </div>
  );
};

const Content = () => {
  const t = (n) => (
    <div key={n}>
      <h1>Title {n}</h1>
      <p>Paragraph {n}.1</p>
      <p>Paragraph {n}.2</p>
    </div>)
  return (
    <div>
      {[t(1),t(2),t(3),t(4),t(5),t(6),t(7),t(8)]}
    </div>
  );
};

const App = () => {
  const [isOpen, setIsOpen] = React.useState(false);
  
  React.useEffect(() => {
    if (isOpen) {
      document.body.style.overflow = 'hidden';
    }
    return () => {
      document.body.style.overflow = null;
    };
  }, [isOpen]);

  return (
    <div className="app">
      <Navbar isOpen={isOpen} setIsOpen={setIsOpen} />
      <div className="content">
        <Content />
        {isOpen ? <div className="modaloverlay"/> : ''}
      </div>
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
.app {
  width: 400px;
  margin-top: 50px;
}
.navbar {
  position: fixed;
  top: 0px;
  width: 100vw;
  width: 400px;
  background-color: yellow;
  text-align: center;
  z-index: 1000;
}
.content {
  background-color: green;
}
.modaloverlay{
  position:fixed;
  top:0;left:0;width:100vw;height:100vh;
  background-color:black;
  opacity:0.5;
  z-index: 999;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

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

相关问题