如何在 reactjs 中添加下拉列表?
How to add dropdown in reactjs?
我正在制作一个简单的 React 应用程序,其中要求我需要使用 pure reactjs 制作下拉菜单。下拉菜单也需要响应。
预计会发生以下 mouse/click 事件。
- 桌面屏幕等较大的设备:悬停时
- 移动设备等小型设备:点击时
工作代码段
function App() {
React.useEffect(() => {
const has_submenu = document.querySelector(".has-submenu");
const submenu = document.querySelector(".submenu");
const submenu_height = submenu && submenu.childElementCount * 34;
if (has_submenu && submenu && submenu_height) {
has_submenu.addEventListener("mouseover", function () {
submenu.style.height = submenu_height + "px";
});
has_submenu.addEventListener("mouseout", function () {
submenu.style.height = "0px";
});
submenu.addEventListener("mouseover", function () {
submenu.style.height = submenu_height + "px";
});
submenu.addEventListener("mouseout", function () {
submenu.style.height = "0px";
});
}
}, []);
return (
<nav>
<ul>
<li className="menu-item has-submenu inline-flex"> Account </li>
<ul className="submenu">
<li className="submenu-item submenu1">
Profile
</li>
<li className="submenu-item submenu1">
Change Password
</li>
</ul>
</ul>
</nav>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
.submenu {
background: #fff;
position: absolute;
list-style-type: none;
padding: 0;
height: 0px;
overflow: hidden;
color: #000;
cursor: pointer;
transition: height 0.33333s ease-in;
}
.submenu-item {
padding: 2px 16px;
list-style-position: outside;
transition: background 0.33333s;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
如果你看一下上面的代码,那么你可以看到在鼠标悬停时 account
,子菜单列在下面。
要求:
尽管它有效,但我觉得我已经使用反应之外的范围实现了它,因为我正在使用 dom methods
并设置 submenu
部分的高度。
是否有任何纯粹的反应方式来实现这一目标?
如果可以,请帮助我重构上面的代码片段,以实现桌面视图(悬停时)和移动视图(单击时)的菜单下拉菜单。
预期输出:
桌面:(悬停时)
Dashboard Account Logout
| -- Profile -- |
| -- Change Password -- |
手机:(点击)
Dashboard
Account
| -- Profile -- |
| -- Change Password -- |
Logout
React 允许您在组件中控制 state
。有很多方法可以解决这个问题,但我将在下面举一个小例子。
您将想要对事件做出反应并更改 state
。每次 state
更新时,您的组件将被重新渲染。
const MAGIC_NUMBER = 34;
const MyApp = () => {
const subMenuRef = React.createRef();
const [ isMenuOpen, setMenuOpen ] = React.useState(false);
const [ menuHeight, setMenuHeight ] = React.useState(0);
const openMenu = () => setMenuOpen(true);
const closeMenu = () => setMenuOpen(false);
React.useEffect(() => {
if (!subMenuRef.current) { return; }
setMenuHeight(subMenuRef.current.childElementCount * MAGIC_NUMBER);
}, [subMenuRef.current]);
return (
<nav>
<ul>
<li
className="menu-item inline-flex"
onMouseOver={openMenu}
onMouseOut={closeMenu}
>
Account
</li>
<ul
className="submenu"
ref={subMenuRef}
style={{height: isMenuOpen ? menuHeight : 0}}
onMouseOver={openMenu}
onMouseOut={closeMenu}
>
<li className="submenu-item submenu1">
Profile
</li>
<li className="submenu-item submenu1">
Change Password
</li>
</ul>
</ul>
</nav>
);
};
ReactDOM.render(<MyApp />, document.querySelector('#app'));
.submenu {
background: #fff;
position: absolute;
list-style-type: none;
padding: 0;
height: 0px;
overflow: hidden;
color: #000;
cursor: pointer;
transition: height 0.33333s ease-in;
border: 1px solid #777;
}
.submenu-item {
padding: 2px 16px;
list-style-position: outside;
transition: background 0.33333s;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
上面发生了很多事情,所以我会在这里分解一下..
- 我们直接向我们的元素添加了事件侦听器。
- React 允许我们直接附加这些事件监听器而无需访问 DOM
- 我们添加了一些状态来跟踪菜单的 open/close 状态
- 在我们的事件处理程序中,我们只需翻转状态,一切正常。
- 我们向元素添加条件逻辑来处理状态变化。 (改变菜单时的高度opens/closes)
- 我们使用
ref
直接访问 DOM 以获取子元素计数。 Documentation
- 如果您完全处于反应状态,这些子项可能是您正在迭代的列表,您可以简单地获取它的长度。
- 通常您不需要访问底层 DOM 因为大多数事情将在 React 本身中处理。
PS:尽可能避免使用幻数。在本例中,您的值为 34
。这代表什么?它为什么在这里?如果您必须使用精确的高度,请改为使用 rem
或 lineHeight
进行 css 计算
我正在制作一个简单的 React 应用程序,其中要求我需要使用 pure reactjs 制作下拉菜单。下拉菜单也需要响应。
预计会发生以下 mouse/click 事件。
- 桌面屏幕等较大的设备:悬停时
- 移动设备等小型设备:点击时
工作代码段
function App() {
React.useEffect(() => {
const has_submenu = document.querySelector(".has-submenu");
const submenu = document.querySelector(".submenu");
const submenu_height = submenu && submenu.childElementCount * 34;
if (has_submenu && submenu && submenu_height) {
has_submenu.addEventListener("mouseover", function () {
submenu.style.height = submenu_height + "px";
});
has_submenu.addEventListener("mouseout", function () {
submenu.style.height = "0px";
});
submenu.addEventListener("mouseover", function () {
submenu.style.height = submenu_height + "px";
});
submenu.addEventListener("mouseout", function () {
submenu.style.height = "0px";
});
}
}, []);
return (
<nav>
<ul>
<li className="menu-item has-submenu inline-flex"> Account </li>
<ul className="submenu">
<li className="submenu-item submenu1">
Profile
</li>
<li className="submenu-item submenu1">
Change Password
</li>
</ul>
</ul>
</nav>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
.submenu {
background: #fff;
position: absolute;
list-style-type: none;
padding: 0;
height: 0px;
overflow: hidden;
color: #000;
cursor: pointer;
transition: height 0.33333s ease-in;
}
.submenu-item {
padding: 2px 16px;
list-style-position: outside;
transition: background 0.33333s;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
如果你看一下上面的代码,那么你可以看到在鼠标悬停时 account
,子菜单列在下面。
要求:
尽管它有效,但我觉得我已经使用反应之外的范围实现了它,因为我正在使用 dom methods
并设置 submenu
部分的高度。
是否有任何纯粹的反应方式来实现这一目标?
如果可以,请帮助我重构上面的代码片段,以实现桌面视图(悬停时)和移动视图(单击时)的菜单下拉菜单。
预期输出:
桌面:(悬停时)
Dashboard Account Logout
| -- Profile -- |
| -- Change Password -- |
手机:(点击)
Dashboard
Account
| -- Profile -- |
| -- Change Password -- |
Logout
React 允许您在组件中控制 state
。有很多方法可以解决这个问题,但我将在下面举一个小例子。
您将想要对事件做出反应并更改 state
。每次 state
更新时,您的组件将被重新渲染。
const MAGIC_NUMBER = 34;
const MyApp = () => {
const subMenuRef = React.createRef();
const [ isMenuOpen, setMenuOpen ] = React.useState(false);
const [ menuHeight, setMenuHeight ] = React.useState(0);
const openMenu = () => setMenuOpen(true);
const closeMenu = () => setMenuOpen(false);
React.useEffect(() => {
if (!subMenuRef.current) { return; }
setMenuHeight(subMenuRef.current.childElementCount * MAGIC_NUMBER);
}, [subMenuRef.current]);
return (
<nav>
<ul>
<li
className="menu-item inline-flex"
onMouseOver={openMenu}
onMouseOut={closeMenu}
>
Account
</li>
<ul
className="submenu"
ref={subMenuRef}
style={{height: isMenuOpen ? menuHeight : 0}}
onMouseOver={openMenu}
onMouseOut={closeMenu}
>
<li className="submenu-item submenu1">
Profile
</li>
<li className="submenu-item submenu1">
Change Password
</li>
</ul>
</ul>
</nav>
);
};
ReactDOM.render(<MyApp />, document.querySelector('#app'));
.submenu {
background: #fff;
position: absolute;
list-style-type: none;
padding: 0;
height: 0px;
overflow: hidden;
color: #000;
cursor: pointer;
transition: height 0.33333s ease-in;
border: 1px solid #777;
}
.submenu-item {
padding: 2px 16px;
list-style-position: outside;
transition: background 0.33333s;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
上面发生了很多事情,所以我会在这里分解一下..
- 我们直接向我们的元素添加了事件侦听器。
- React 允许我们直接附加这些事件监听器而无需访问 DOM
- 我们添加了一些状态来跟踪菜单的 open/close 状态
- 在我们的事件处理程序中,我们只需翻转状态,一切正常。
- 我们向元素添加条件逻辑来处理状态变化。 (改变菜单时的高度opens/closes)
- 我们使用
ref
直接访问 DOM 以获取子元素计数。 Documentation- 如果您完全处于反应状态,这些子项可能是您正在迭代的列表,您可以简单地获取它的长度。
- 通常您不需要访问底层 DOM 因为大多数事情将在 React 本身中处理。
PS:尽可能避免使用幻数。在本例中,您的值为 34
。这代表什么?它为什么在这里?如果您必须使用精确的高度,请改为使用 rem
或 lineHeight