React Material UI 从自动完成中打开模式失去焦点
React Material UI open modal from within autocomplete lose focus
我正在使用 material-ui 库,我需要一个自动完成功能,其中自动完成功能中的每个项目都可以点击并打开一个模式。
大体的结构是:
const ModalBtn = () => {
...
return (
<>
<button ... (on click set modal to open)
<Modal ...
</>
);
}
const AutoCompleteWithBtns = () => {
return (
<Autocomplete
renderTags={(value, getTagProps) =>
value.map((option, index) => <ModalBtn />)
}
...
/>
);
}
Note that the ModalBtn is a component that cannot be divided into two components of Button and Modal.
问题是,当您单击模态内的按钮时 - 焦点保留在自动完成内,并且模态永远不会获得焦点(如果我在模态内有输入 - 我无法编写里面的任何东西)。
尝试了所有标准的 autocomplete/modal 焦点相关道具(disableEnforceFocus
、disableEnforceFocus
等...),但没有任何效果。
这里是working codesandbox example。如您所见 - 如果您单击不在自动完成组件内的按钮 - 一切正常(您可以在输入字段内添加文本)。如果您单击自动完成内的按钮 - 模态内的输入字段不可编辑(您失去焦点)。
这是问题的一个例子:
您的代码中的问题是模态框是从 AutoComplete
组件的标记内呈现的,这不正常,因为组件的可见性、组件的层次结构是问题所在。
修复方法是将 Modal
移动到 FixedTags
组件中,并将打开的处理程序传递给 renderTags
属性中的 ModalBtn
;
我已经用一个工作变体更新了你的沙箱 HERE
变化如下
const ModalBtn = ({ handleOpen }) => (
<button type="button" onClick={handleOpen}>
Open Modal (not working)
</button>
);
const FixedTags = function() {
const classes = useStyles();
const [modalStyle] = React.useState(getModalStyle);
const [open, setOpen] = React.useState(false);
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<>
<Autocomplete
multiple
options={autoCompleteItems}
getOptionLabel={option => option.title}
defaultValue={[autoCompleteItems[1], autoCompleteItems[2]]}
renderTags={(value, getTagProps) =>
value.map((option, index) => <ModalBtn handleOpen={handleOpen} />)
}
style={{ width: 500 }}
renderInput={params => (
<TextField
{...params}
label="Fixed tag"
variant="outlined"
placeholder="items..."
/>
)}
/>
<Modal open={open} onClose={handleClose}>
<div style={modalStyle} className={classes.paper}>
<h2 style={{ color: "red" }}>This one doesn't work</h2>
<p>Text field is not available</p>
<TextField label="Filled" variant="filled" /> <br />
<br />
<br />
<FixedTags label="Standard" />
</div>
</Modal>
</>
);
};
从 Autocomplete
中呈现 Modal
的问题是事件从 Modal
传播到 Autocomplete
。特别是,单击和鼠标按下事件均由 Autocomplete
以导致您的情况出现问题的方式处理。这主要是为了在您与 Autocomplete
.
的不同部分交互时将焦点保持在正确的位置
下面(来自 https://github.com/mui-org/material-ui/blob/v4.9.11/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js#L842)是 Autocomplete
代码中妨碍您的部分:
// Prevent input blur when interacting with the combobox
const handleMouseDown = (event) => {
if (event.target.getAttribute('id') !== id) {
event.preventDefault();
}
};
// Focus the input when interacting with the combobox
const handleClick = () => {
inputRef.current.focus();
if (
selectOnFocus &&
firstFocus.current &&
inputRef.current.selectionEnd - inputRef.current.selectionStart === 0
) {
inputRef.current.select();
}
firstFocus.current = false;
};
在可聚焦元素上发生鼠标按下事件时,浏览器的默认行为是让该元素获得焦点,但 Autocomplete
的鼠标按下处理程序会调用 event.preventDefault()
来阻止此默认行为从而防止鼠标按下事件引起的焦点变化(因此焦点停留在 Modal
本身,如其蓝色焦点轮廓所示)。但是,您可以使用 Tab 键成功地将焦点移动到模态框的 TextField,因为没有什么可以阻止焦点更改机制。
即使您单击 Autocomplete
的其他部分,Autocomplete
单击处理程序仍将焦点放在 Autocomplete
的输入上。当您的 Modal
打开时,其效果是当您在 Modal
中单击时,焦点会短暂地移动到 Autocomplete
输入元素,但焦点会立即返回到 Modal
由于其 "enforce focus" 功能。如果您将 disableEnforceFocus
属性 添加到 Modal
、you'll see,那么当您单击 Modal
(例如在 TextField 上)时,光标将保留在输入中Autocomplete
.
解决方法是确保这两个事件不会传播到Modal
之外。通过为 Modal
上的单击和鼠标按下事件调用 event.stopPropagation()
,它可以防止在 [=12= 中发生这两个事件时执行这两个事件的 Autocomplete
功能].
<Modal
onClick={event => event.stopPropagation()}
onMouseDown={event => event.stopPropagation()}
...
相关回答:
我正在使用 material-ui 库,我需要一个自动完成功能,其中自动完成功能中的每个项目都可以点击并打开一个模式。
大体的结构是:
const ModalBtn = () => {
...
return (
<>
<button ... (on click set modal to open)
<Modal ...
</>
);
}
const AutoCompleteWithBtns = () => {
return (
<Autocomplete
renderTags={(value, getTagProps) =>
value.map((option, index) => <ModalBtn />)
}
...
/>
);
}
Note that the ModalBtn is a component that cannot be divided into two components of Button and Modal.
问题是,当您单击模态内的按钮时 - 焦点保留在自动完成内,并且模态永远不会获得焦点(如果我在模态内有输入 - 我无法编写里面的任何东西)。
尝试了所有标准的 autocomplete/modal 焦点相关道具(disableEnforceFocus
、disableEnforceFocus
等...),但没有任何效果。
这里是working codesandbox example。如您所见 - 如果您单击不在自动完成组件内的按钮 - 一切正常(您可以在输入字段内添加文本)。如果您单击自动完成内的按钮 - 模态内的输入字段不可编辑(您失去焦点)。
这是问题的一个例子:
您的代码中的问题是模态框是从 AutoComplete
组件的标记内呈现的,这不正常,因为组件的可见性、组件的层次结构是问题所在。
修复方法是将 Modal
移动到 FixedTags
组件中,并将打开的处理程序传递给 renderTags
属性中的 ModalBtn
;
我已经用一个工作变体更新了你的沙箱 HERE
变化如下
const ModalBtn = ({ handleOpen }) => (
<button type="button" onClick={handleOpen}>
Open Modal (not working)
</button>
);
const FixedTags = function() {
const classes = useStyles();
const [modalStyle] = React.useState(getModalStyle);
const [open, setOpen] = React.useState(false);
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<>
<Autocomplete
multiple
options={autoCompleteItems}
getOptionLabel={option => option.title}
defaultValue={[autoCompleteItems[1], autoCompleteItems[2]]}
renderTags={(value, getTagProps) =>
value.map((option, index) => <ModalBtn handleOpen={handleOpen} />)
}
style={{ width: 500 }}
renderInput={params => (
<TextField
{...params}
label="Fixed tag"
variant="outlined"
placeholder="items..."
/>
)}
/>
<Modal open={open} onClose={handleClose}>
<div style={modalStyle} className={classes.paper}>
<h2 style={{ color: "red" }}>This one doesn't work</h2>
<p>Text field is not available</p>
<TextField label="Filled" variant="filled" /> <br />
<br />
<br />
<FixedTags label="Standard" />
</div>
</Modal>
</>
);
};
从 Autocomplete
中呈现 Modal
的问题是事件从 Modal
传播到 Autocomplete
。特别是,单击和鼠标按下事件均由 Autocomplete
以导致您的情况出现问题的方式处理。这主要是为了在您与 Autocomplete
.
下面(来自 https://github.com/mui-org/material-ui/blob/v4.9.11/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js#L842)是 Autocomplete
代码中妨碍您的部分:
// Prevent input blur when interacting with the combobox
const handleMouseDown = (event) => {
if (event.target.getAttribute('id') !== id) {
event.preventDefault();
}
};
// Focus the input when interacting with the combobox
const handleClick = () => {
inputRef.current.focus();
if (
selectOnFocus &&
firstFocus.current &&
inputRef.current.selectionEnd - inputRef.current.selectionStart === 0
) {
inputRef.current.select();
}
firstFocus.current = false;
};
在可聚焦元素上发生鼠标按下事件时,浏览器的默认行为是让该元素获得焦点,但 Autocomplete
的鼠标按下处理程序会调用 event.preventDefault()
来阻止此默认行为从而防止鼠标按下事件引起的焦点变化(因此焦点停留在 Modal
本身,如其蓝色焦点轮廓所示)。但是,您可以使用 Tab 键成功地将焦点移动到模态框的 TextField,因为没有什么可以阻止焦点更改机制。
即使您单击 Autocomplete
的其他部分,Autocomplete
单击处理程序仍将焦点放在 Autocomplete
的输入上。当您的 Modal
打开时,其效果是当您在 Modal
中单击时,焦点会短暂地移动到 Autocomplete
输入元素,但焦点会立即返回到 Modal
由于其 "enforce focus" 功能。如果您将 disableEnforceFocus
属性 添加到 Modal
、you'll see,那么当您单击 Modal
(例如在 TextField 上)时,光标将保留在输入中Autocomplete
.
解决方法是确保这两个事件不会传播到Modal
之外。通过为 Modal
上的单击和鼠标按下事件调用 event.stopPropagation()
,它可以防止在 [=12= 中发生这两个事件时执行这两个事件的 Autocomplete
功能].
<Modal
onClick={event => event.stopPropagation()}
onMouseDown={event => event.stopPropagation()}
...
相关回答: