我想在 React 中做一个下拉菜单。单击一个按钮应打开一个子菜单。在子菜单外单击应将其关闭

I want to make a dropdown in React. Clicking a button should open a submenu. Clicking outside of the submenu should close it

这是我现有的工作代码。这工作正常,除了如果我在子菜单外单击,当它打开时,子菜单保持打开状态。

class UserTypeDropdown extends React.Component
  constructor: (props) ->
    super(props)
    @state =
      display_submenu: false
  @propTypes:
    selected: React.PropTypes.string.isRequired

  submenu_display:->
    if @state.display_submenu
      'block'
    else
      'none'
  button_class_names:->
    classNames(
        'select-btn ': true,
        'user_role ': @props.selected is 'user',
        'admin_role ': @props.selected is 'admin'
        )

  selected_text:->
    if @props.selected == 'user'
      'User'
    else
      'Administrator'

  render:->
    div {className: 'user-type-dropdown'},
      button { className: @button_class_names(), onClick: @_toggleSubmenu },
        @selected_text()
      ul {className: 'submenu submenu_content access_submenu', style: {display: @submenu_display()}},
        li {onClick: @select_admin},
          a {},
            'Administrator'
        li {onClick: @select_user},
          a {},
            'User'
  _toggleSubmenu: =>
    @setState display_submenu: !@state.display_submenu
  select_admin: =>
    @_toggleSubmenu()
    actions.setUserRole('admin')
  select_user: =>
    @_toggleSubmenu()
    actions.setUserRole('user')

我想实现在子菜单打开时在其外部单击,然后将其关闭。

我已经了解了如何在 React 中执行此操作,并且遇到了很多建议说我应该使用 onFocus 和 onBlur 而不是 onClick

这对我来说很有意义,因为它意味着只有在浏览器中获得焦点时,下拉菜单才应该打开。所以我的渲染函数和方法变成了。

  render:->
    div {className: 'user-type-dropdown'},
      button { className: @button_class_names(), onFocus: @_toggleSubmenu, onBlur: @_toggleSubmenu },
        @selected_text()
      ul {className: 'submenu submenu_content access_submenu', style: {display: @submenu_display()}},
        li {onClick: @select_admin},
          a {},
            'Administrator'
        li {onClick: @select_user},
          a {},
            'User'
  _toggleSubmenu: =>
    @setState display_submenu: !@state.display_submenu
  select_admin: =>
    actions.setUserRole('admin')
  select_user: =>
    actions.setUserRole('user')

但是 onFocus:onBlur:button 元素上, 现在点击 li 中的任何一个都不会触发 @select_admin@select_user 它只会触发 @_toggle_submenu 并且点击似乎不会传播/冒泡到 li 下面的元素..

通过阅读 React Event Documentation and This Focus and hotkeys guide 我可以看出事件应该会冒泡,但对我来说它们根本没有。

我是 React Coffescript/JS 世界的新手,所以请原谅任何不正确的命名约定。

我想我的理解一定是有缺陷的,因为我在任何地方都找不到这个问题的答案。

如有任何帮助,我们将不胜感激。

您的问题是:只要您单击一个项目,onBlur 事件就会先触发。这会导致重新渲染(因为你做了 setState)。因此您的 onClick 事件永远不会是 运行.

解决此问题的方法(使用 onFocus 和 onBlur)是重新安排您的 HTML 设置:

  • 确保您的主菜单项可以有焦点(<button> 已经可以)
  • 确保你的子菜单不能有焦点(<li> 没问题)
  • 确保你的子菜单在你的主菜单组件内部(你需要更改它)

这样,如果您单击其中一个子项,您的主菜单项就不会失去焦点。

您可以找到一个简单的(仅 HTML 和 javascript)JSBIN example here