this.wrapperRef.current.contains(element) returns false 虽然元素是孙子
this.wrapperRef.current.contains(element) returns false although element is a grand child
包装器 EditModal
组件带有 onClickOutside
事件。此模式的子组件是 Material-UI Select
。单击 MenuItem
会触发 onClickOutside
,从而在未选择新值的情况下关闭模式。
问题的根源是 this.wrapperRef.current.contains(element)
返回 false
,即使 MenuItem
是 EditModal
的孙子。
为什么会这样?如何避免这种行为?
https://codesandbox.io/s/select-inside-edit-modal-l69zj?file=/src/edit-modal.js
(代码改编自this blog)
import React, { createRef } from "react";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
class EditModal extends React.Component {
constructor(props) {
super(props);
this.wrapperRef = createRef();
this.state = { value: props.initialValue };
}
componentDidMount() {
document.body.addEventListener("mousedown", this.onClickOutside);
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.onClickOutside);
}
onClickOutside = (e) => {
const { onClose } = this.props;
const element = e.target;
if (this.wrapperRef.current && !this.wrapperRef.current.contains(element)) {
console.log(this.wrapperRef.current.contains(element));
e.preventDefault();
e.stopPropagation();
onClose();
}
};
onChange = (e) => {
const { onClose } = this.props;
this.setState({ value: e.target.value });
this.props.onChange(e.target.value);
onClose();
};
render() {
const value = this.state.value;
return (
<div className="modal--overlay">
<div className="modal" ref={this.wrapperRef}>
<h1>Select a new value</h1>
<Select
id="demo-customized-select"
value={value}
color="primary"
onChange={this.onChange}
>
<MenuItem value={"A"}>A</MenuItem>
<MenuItem value={"B"}>B</MenuItem>
<MenuItem value={"C"}>C</MenuItem>
</Select>
</div>
</div>
);
}
}
export default EditModal;
一位同事找到了答案。 Material-UI 生成的弹出菜单未作为 DOM 中 Select
的子项放置。
要修复 onClickOutside
,应使用 Select
属性 MenuProps.
添加引用此菜单的附加条件
https://codesandbox.io/s/select-inside-edit-modal-forked-wrz7t?file=/src/edit-modal.js:1382-1448
[...]
this.wrapperRef = createRef();
this.inputRef = createRef();
[...]
if (
this.wrapperRef.current &&
!this.wrapperRef.current.contains(element) &&
(this.inputRef.current === null ||
(this.inputRef.current && !this.inputRef.current.contains(element)))
) {
[...]
<Select
MenuProps={{
ref: this.inputRef
}}
id="demo-customized-select"
value={value}
color="primary"
onChange={this.onChange}
>
[...]
包装器 EditModal
组件带有 onClickOutside
事件。此模式的子组件是 Material-UI Select
。单击 MenuItem
会触发 onClickOutside
,从而在未选择新值的情况下关闭模式。
问题的根源是 this.wrapperRef.current.contains(element)
返回 false
,即使 MenuItem
是 EditModal
的孙子。
为什么会这样?如何避免这种行为?
https://codesandbox.io/s/select-inside-edit-modal-l69zj?file=/src/edit-modal.js (代码改编自this blog)
import React, { createRef } from "react";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
class EditModal extends React.Component {
constructor(props) {
super(props);
this.wrapperRef = createRef();
this.state = { value: props.initialValue };
}
componentDidMount() {
document.body.addEventListener("mousedown", this.onClickOutside);
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.onClickOutside);
}
onClickOutside = (e) => {
const { onClose } = this.props;
const element = e.target;
if (this.wrapperRef.current && !this.wrapperRef.current.contains(element)) {
console.log(this.wrapperRef.current.contains(element));
e.preventDefault();
e.stopPropagation();
onClose();
}
};
onChange = (e) => {
const { onClose } = this.props;
this.setState({ value: e.target.value });
this.props.onChange(e.target.value);
onClose();
};
render() {
const value = this.state.value;
return (
<div className="modal--overlay">
<div className="modal" ref={this.wrapperRef}>
<h1>Select a new value</h1>
<Select
id="demo-customized-select"
value={value}
color="primary"
onChange={this.onChange}
>
<MenuItem value={"A"}>A</MenuItem>
<MenuItem value={"B"}>B</MenuItem>
<MenuItem value={"C"}>C</MenuItem>
</Select>
</div>
</div>
);
}
}
export default EditModal;
一位同事找到了答案。 Material-UI 生成的弹出菜单未作为 DOM 中 Select
的子项放置。
要修复 onClickOutside
,应使用 Select
属性 MenuProps.
https://codesandbox.io/s/select-inside-edit-modal-forked-wrz7t?file=/src/edit-modal.js:1382-1448
[...]
this.wrapperRef = createRef();
this.inputRef = createRef();
[...]
if (
this.wrapperRef.current &&
!this.wrapperRef.current.contains(element) &&
(this.inputRef.current === null ||
(this.inputRef.current && !this.inputRef.current.contains(element)))
) {
[...]
<Select
MenuProps={{
ref: this.inputRef
}}
id="demo-customized-select"
value={value}
color="primary"
onChange={this.onChange}
>
[...]