javascript - MATERIAL-UI React - 另一个 Popper 的 Popper

标签 javascript reactjs material-ui popper.js react-popper

我正在开发一个日历应用程序。
问题:单击 popper 的 popper 会关闭两个 popper,因为它会触发关闭它的第一个 popper 的 click outside 事件。
我有一个组件 <Event />使用 Material-UI React <Popper />它可以正常工作。将其与 <AwayClickListener />单击外部时它会关闭,并在弹出器内部单击时保持打开状态。我创建了 <Events />这是 <Event /> 的列表.
 event details popper
单击 + 更多文本时,应在单元格顶部显示包含当天所有事件的弹出器。
波普尔 child 也是<Events /> :
expanded events list
单击一个事件应该会打开一个带有事件详细信息的弹出器,就像在单元格中单击它一样。
因为我使用相同的组件<Events />它做到了,但并不完全符合预期:
单击事件详细信息弹出器会关闭两个弹出器。
这就是问题所在:要求是单击弹出器的外侧将关闭弹出器,但单击内部将使它们保持打开和交互
events list popper with it's event details popper
调试显示单击第二个 popper 会触发第一个 popper 的外部单击事件,从而将其关闭。此外,从第一个 popper 中取出 click away 监听器功能,让第二个 popper 在大多数点击中保持打开状态 - 单击其中的某些位置,会触发它的 clicked away 功能,从而将其关闭。例如:单击标题会关闭它,单击位置或摘要 div 不会。

  • 我尝试用 <ClickAwayListener /> 包裹整个单元格.
  • 我尝试用 <ClickAwayListener /> 包裹 popper 的 child 。
  • 尝试使用 material-ui-popup-state npm,并提供 popper id 属性。比点击离开时,将目标 ID 与“popper”进行比较,如果相等则保持打开状态。但是,从 onClickAway 事件的事件对象中提取的 id 是空字符串。即使单击弹出器。

  • 代码
    <Popper> - Material ui popper 的服装包装
    const popper = ({
      placement,
      open,
      anchorEl,
      handleClickAway=null,
      title,
      handleCloseClick=null,
      children,
      popperStyle = {},
      calendarPopoverClass = ''
    }) => {
      const useStyles = makeStyles({
        Popper: popperStyle
      })
      const styles = useStyles();
      return (
        <Popper modifiers={{
          flip: {
            enabled: false,
          },
          preventOverflow: {
            enabled: false,
            boundariesElement: 'scrollParent',
          }
        }}
          className={styles.Popper}
          placement={placement}
          open={open}
          anchorEl={anchorEl}
        >
          <ClickAwayListener onClickAway={handleClickAway}>
            <CalendarPopover className={st(classes[calendarPopoverClass])} isShown withArrow={false} title={title} onClose={handleCloseClick}>
              {children}
            </CalendarPopover>
          </ClickAwayListener>
        </Popper>
      )
    }
    
    <Event />
    const event = ({ PROPS }) => {
    const [expanded, setExpanded] = React.useState(null);
    const closeExpanded = () => setExpanded(null)
    return (
            <>
              <div
                className={st(classes.Event, { isTimeShown, isNextWeekFirstFiller, isLastFiller, isMultiDay, isAllDay, isFiller })}
                style={inlineStyle}
                onClick={onEventClick}
              >
                <div className={classes.Time}>{timeToDisplay}</div>
                <div className={classes.Title}>{title}</div>
              </div>
              <Popper
          placement={popperPlacement}
          title={title}
          handleCloseClick={closeExpanded}
          handleClickAway={closeExpanded}
          open={Boolean(expanded)}
          anchorEl={expanded}
          popperStyle={popperStyle}
          calendarPopoverClass='Event'
        >
          <ExpandedEvent
            startDate={startDate}
            endDate={endDate}
            location={location}
            summary={summary}
          />
        </Popper>
            </>
          );
    }
    
    <Events />
    const Events = ({ events, isTimeShown, localeToggle, popperPlacement, popperStyle, handleShowMoreClick=null }) => {
      const eventsToShow: JSX.Element[] = [];
      if (events.length > 0) {
        let eventsToShowAmount = 3;
        const moreEventsCount = events.length - eventsToShowAmount;
        eventsToShowAmount = moreEventsCount > 0 ? eventsToShowAmount : events.length;
        for (let i = 0; i < eventsToShowAmount; i++) {
          eventsToShow.push(
            <Event
              key={events[i].id}
              {...events[i]}
              isTimeShown={isTimeShown}
              popperPlacement={popperPlacement}
              popperStyle={popperStyle}
            />
          )
        }
        if (moreEventsCount > 0) {
          eventsToShow.push(<ShowMore key='ShowMore' handleClick={handleShowMoreClick} moreEventsCount={moreEventsCount} />)
        }
      }
    
      return (
        <div className={classes.Events}>
          {eventsToShow}
        </div>
      );
    }
    
    <MonthlyCell />
    const MonthlyCell = ({
      events,
      isTimeShown,
      popperPlacement,
      popperStyle
    }) => {
    
      const [expandedEvents, setExpandedEvents] = React.useState(null);
      const cell = React.useRef<HTMLDivElement>(null)
    
    
      const eventsList = (handleShowMoreClick = null) => (
        <Events
          events={events}
          isTimeShown={isTimeShown}
          localeToggle={true}
          popperPlacement={popperPlacement}
          popperStyle={popperStyle}
          handleShowMoreClick={handleShowMoreClick}
        />
      );
    
      const handleShowMoreClick = () => setExpandedEvents(eventsList());
    
      const closeExpandedEvents = () => {
        setExpandedEvents(null);
      }
    
      return (
        <>
          <div ref={cell} className={classes.MonthlyCell} >
            {eventsList(handleShowMoreClick)}
          </div>
          <Popper
            placement='left'
            open={Boolean(expandedEvents)}
            title='hello'
            handleClickAway={closeExpandedEvents}
            anchorEl={cell.current}
            popperStyle={{ left: '17% !important' }}
            handleCloseClick={closeExpandedEvents}
          >
            {eventsList()}
          </Popper>
        </>
      );
    }
    
    希望它足够清楚。让我知道是否需要其他任何东西。
    谢谢
    编辑 1
    另一种尝试是给父 popper 更大的 z-index,但它没有用

    最佳答案

    解决方案是将popper child 包围在一个div中。
    我使用的组件导致了这种不需要的行为,因为它没有 forwardRef 支持。所以添加 div 包装器解决了这个问题。
    另外,删除修饰符属性:

    <Popper 
          // modifiers={{
          // flip: {
          //  enabled: false,
          // },
          // preventOverflow: {
          //   enabled: false,
          //   boundariesElement: 'scrollParent',
         //  }
        // }}
    
    工作解决方案链接:https://codesandbox.io/s/popper-in-a-popper-s6dfr?file=/src/Popper/Popper.js:372-519

    关于javascript - MATERIAL-UI React - 另一个 Popper 的 Popper,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63361075/

    相关文章:

    reactjs - 在 react 中显示 Flash 消息

    reactjs - 将属性从 DropzoneArea 传递到 Dropzone

    reactjs - 在不同的路由器中登录 -ReactJs-

    javascript - 关于javascript/jquery缓存的问题

    javascript - 使用 Konva.Node.create 加载时,无法在 konva js 中拖动和变换矩形

    javascript - 响应 header 为空

    reactjs - 在新的 @material-ui/core 中使用 withStyles 和 Typescript

    javascript - 设置变量 if...then javascript

    javascript - React JSX 连接多个 {this.state} {this.props}

    javascript - 为什么我的类型在 React 和 TypeScript 中为 null?