MATERIAL-UI React - 另一个 Popper 的 Popper
MATERIAL-UI React - Popper of another Popper
我正在开发日历应用程序。
问题:单击弹出器的弹出器会关闭两个弹出器,因为它会触发关闭它的第一个弹出器的外部点击事件。
我有一个组件 <Event />
,它使用 Material-UI React <Popper />
,并且可以正常工作。将它与 <AwayClickListener />
组合在一起,它在单击外侧时关闭,在弹出器内部单击时保持打开状态。我创建了 <Events />
,它是 <Event />
.
的列表
当单击 + 更多文本时,包含当天所有事件的弹出窗口应出现在单元格顶部。
波普尔 children 也是 <Events />
:
点击一个事件应该会打开一个带有事件详细信息的弹出窗口,就像在单元格中点击它一样。
因为我使用相同的组件 <Events />
它会这样做,但并不完全符合预期:
单击事件详细信息弹出窗口将关闭两个弹出窗口。
这就是问题所在:要求ui评论是点击 poppers 的外侧将关闭 poppers,但点击内侧将使它们保持打开和交互状态
调试显示单击第二个弹出器会触发第一个弹出器的外部单击事件,从而将其关闭。此外,从第一个 popper 中取出 click away 侦听器功能,让第二个 popper 对于大多数点击保持打开状态 - 单击其中的某些位置,触发它的 clicked away 功能并关闭它。例如:单击标题将其关闭,单击位置或摘要 div 则不会。
- 我尝试用
<ClickAwayListener />
包裹整个单元格。
- 我尝试用
<ClickAwayListener />
包装 popper 的 children
- 尝试使用 material-ui-popup-state npm,并提供了 popper id 属性。比点击离开时,将目标 ID 与 'popper' 进行比较,如果相等,则保持打开状态。但是,从 onClickAway 事件的事件 object 中提取的 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
另一种尝试是将 parent popper 设置得更大 z-index,但没有成功
解决方案是在 div 中围绕波普尔 children。
我使用的组件导致了这种 un-wanted 行为,因为它没有 forwardRef 支持。所以添加 div 包装器解决了这个问题。
此外,删除修饰符属性:
<Popper
// modifiers={{
// flip: {
// enabled: false,
// },
// preventOverflow: {
// enabled: false,
// boundariesElement: 'scrollParent',
// }
// }}
link 工作解决方案:https://codesandbox.io/s/popper-in-a-popper-s6dfr?file=/src/Popper/Popper.js:372-519
我正在开发日历应用程序。
问题:单击弹出器的弹出器会关闭两个弹出器,因为它会触发关闭它的第一个弹出器的外部点击事件。
我有一个组件 <Event />
,它使用 Material-UI React <Popper />
,并且可以正常工作。将它与 <AwayClickListener />
组合在一起,它在单击外侧时关闭,在弹出器内部单击时保持打开状态。我创建了 <Events />
,它是 <Event />
.
当单击 + 更多文本时,包含当天所有事件的弹出窗口应出现在单元格顶部。
波普尔 children 也是 <Events />
:
点击一个事件应该会打开一个带有事件详细信息的弹出窗口,就像在单元格中点击它一样。
因为我使用相同的组件 <Events />
它会这样做,但并不完全符合预期:
单击事件详细信息弹出窗口将关闭两个弹出窗口。
这就是问题所在:要求ui评论是点击 poppers 的外侧将关闭 poppers,但点击内侧将使它们保持打开和交互状态
调试显示单击第二个弹出器会触发第一个弹出器的外部单击事件,从而将其关闭。此外,从第一个 popper 中取出 click away 侦听器功能,让第二个 popper 对于大多数点击保持打开状态 - 单击其中的某些位置,触发它的 clicked away 功能并关闭它。例如:单击标题将其关闭,单击位置或摘要 div 则不会。
- 我尝试用
<ClickAwayListener />
包裹整个单元格。 - 我尝试用
<ClickAwayListener />
包装 popper 的 children
- 尝试使用 material-ui-popup-state npm,并提供了 popper id 属性。比点击离开时,将目标 ID 与 'popper' 进行比较,如果相等,则保持打开状态。但是,从 onClickAway 事件的事件 object 中提取的 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
另一种尝试是将 parent popper 设置得更大 z-index,但没有成功
解决方案是在 div 中围绕波普尔 children。 我使用的组件导致了这种 un-wanted 行为,因为它没有 forwardRef 支持。所以添加 div 包装器解决了这个问题。
此外,删除修饰符属性:
<Popper
// modifiers={{
// flip: {
// enabled: false,
// },
// preventOverflow: {
// enabled: false,
// boundariesElement: 'scrollParent',
// }
// }}
link 工作解决方案:https://codesandbox.io/s/popper-in-a-popper-s6dfr?file=/src/Popper/Popper.js:372-519