如何创建一个React下拉菜单(附代码示例)

590 阅读2分钟

一个简短的React教程,通过实例为初学者介绍在React中创建下拉菜单。首先,下拉菜单只是一个HTML选择元素,可以在React的JSX中呈现:

import * as React from 'react';

const App = () => {
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(!open);
  };

  return (
    <div>
      <button onClick={handleOpen}>Dropdown</button>
      {open ? <div>Is Open</div> : <div>Is Closed</div>}
    </div>
  );
};

export default App;

可能缺少的是一个相关的标签,以提示用户这个下拉菜单改变的是什么值:

import * as React from 'react';

import './App.css';

const App = () => {
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(!open);
  };

  return (
    <div className="dropdown">
      <button onClick={handleOpen}>Dropdown</button>
      {open ? (
        <ul className="menu">
          <li className="menu-item">
            <button>Menu 1</button>
          </li>
          <li className="menu-item">
            <button>Menu 2</button>
          </li>
        </ul>
      ) : null}
      {open ? <div>Is Open</div> : <div>Is Closed</div>}
    </div>
  );
};

export default App;

在你的浏览器中,这个下拉菜单已经可以通过单独显示它的每个值来改变它的选择状态。然而,这只是选择的内部HTML状态,还没有被React控制。让我们通过将这个选择从不受控转变为受控来改变这个情况。

.dropdown {
  position: relative;
}

.menu {
  position: absolute;

  list-style-type: none;
  margin: 5px 0;
  padding: 0;

  border: 1px solid grey;
  width: 150px;
}

.menu > li {
  margin: 0;

  background-color: white;
}

.menu > li:hover {
  background-color: lightgray;
}

.menu > li > button {
  width: 100%;
  height: 100%;
  text-align: left;

  background: none;
  color: inherit;
  border: none;
  padding: 5px;
  margin: 0;
  font: inherit;
  cursor: pointer;
}

通过使用React的useState Hook和一个事件处理程序,我们可以通过React的状态来跟踪select的值。我们可以通过更动态地呈现选项来完善这个组件。

import * as React from 'react';

import './App.css';

const App = () => {
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(!open);
  };

  const handleMenuOne = () => {
    // do something
    setOpen(false);
  };

  const handleMenuTwo = () => {
    // do something
    setOpen(false);
  };

  return (
    <div className="dropdown">
      <button onClick={handleOpen}>Dropdown</button>
      {open ? (
        <ul className="menu">
          <li className="menu-item">
            <button onClick={handleMenuOne}>Menu 1</button>
          </li>
          <li className="menu-item">
            <button onClick={handleMenuTwo}>Menu 2</button>
          </li>
        </ul>
      ) : null}
    </div>
  );
};

export default App;

对该组件的这种重构的一个很好的类比是React中的列表组件](/react-list-component/)。接下来我们可能想创建一个可以在整个React项目中多次使用的Dropdown组件。因此,我们将提取它作为一个新的函数组件,并将必要的道具传递给它。

const App = () => {
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(!open);
  };

  const handleMenuOne = () => {
    // do something
    setOpen(false);
  };

  const handleMenuTwo = () => {
    // do something
    setOpen(false);
  };

  return (
    <Dropdown
      open={open}
      trigger={<button onClick={handleOpen}>Dropdown</button>}
      menu={[
        <button onClick={handleMenuOne}>Menu 1</button>,
        <button onClick={handleMenuTwo}>Menu 2</button>,
      ]}
    />
  );
};

const Dropdown = ({ open, trigger, menu }) => {
  return (
    <div className="dropdown">
      {trigger}
      {open ? (
        <ul className="menu">
          {menu.map((menuItem, index) => (
            <li key={index} className="menu-item">{menuItem}</li>
          ))}
        </ul>
      ) : null}
    </div>
  );
};

我们的Dropdown组件现在是一个可重复使用的组件。例如,如果你在React中给你的选择元素一些CSS样式,在你的React项目中使用的每个Dropdown组件都会使用相同的样式。

如果你现在想创建一个下拉组,你可以只使用多个下拉组件并排使用,也许用一些边框和一些对齐方式来设计它们,这样用户就会认为它们是一个下拉组了。

const App = () => {
  const handleMenuOne = () => {
    console.log('clicked one');
  };

  const handleMenuTwo = () => {
    console.log('clicked two');
  };

  return (
    <Dropdown
      trigger={<button>Dropdown</button>}
      menu={[
        <button onClick={handleMenuOne}>Menu 1</button>,
        <button onClick={handleMenuTwo}>Menu 2</button>,
      ]}
    />
  );
};

const Dropdown = ({ trigger, menu }) => {
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(!open);
  };

  return (
    <div className="dropdown">
      {React.cloneElement(trigger, {
        onClick: handleOpen,
      })}
      {open ? (
        <ul className="menu">
          {menu.map((menuItem, index) => (
            <li key={index} className="menu-item">
              {React.cloneElement(menuItem, {
                onClick: () => {
                  menuItem.props.onClick();
                  setOpen(false);
                },
              })}
            </li>
          ))}
        </ul>
      ) : null}
    </div>
  );
};

这就是在React中创建Dropdown组件的方法。如果你是React的初学者,我希望这个教程能帮助你理解一些概念和模式