我在页面上有多个自定义构建下拉组件。我使用setState
触发列表项打开toggleDropdown = (id) => {
this.setState(prevState => ({
[`dropdown${name}`]: !prevState[`dropdown${id}`] //dropdownA, dropdownB, dropdownC and so on
}))
}
如果在菜单打开时单击下拉列表,也会切换它。但是接下来我还有更多的下拉菜单,如果我打开一个下拉列表,其他下拉菜单将会关闭,如何解决这个问题?我做了一个" hacky"混合方式与componentWillMount中的jquery反应,绑定body上的click事件,检查下拉项是否可见,如果是,则关闭它。
我的问题是,有没有更好的做法可以避免使用jquery?
答案 0 :(得分:12)
我的建议是您使用合成事件onFocus
和onBlur
来触发打开/关闭状态。点击元素时会触发onFocus
,而“非焦点”(点击外部)会触发onBlur
。请参阅docs。
焦点/模糊也需要tabIndex
属性/道具来处理非输入类型元素。
我可以建议查看source of react-select以及它们如何处理聚焦/模糊。
以下是一个示例,您可以看到它的演示here
import React from "react";
class Dropdown extends React.Component {
state = {
open: false
};
toggleDropdown() {
this.setState({ open: !this.state.open });
}
render() {
return (
<div
style={{ border: "1px solid #CCC" }}
onBlur={() => this.toggleDropdown()}
onFocus={() => this.toggleDropdown()}
tabIndex="0"
>
Dropdown
{this.state.open && (
<div>
<div>Red</div>
<div>Green</div>
<div>Blue</div>
</div>
)}
</div>
);
}
}
export default Dropdown;
答案 1 :(得分:1)
您可以使用为您提取身体事件处理摘要的react-onclickoutside库。您只需将组件包装在onClickOutside
更高阶的组件中,该组件将在下拉菜单之外的任何时候执行handleClickOutside
回调。这样你就可以拥有一个私密的&#34; open&#34;在所有下拉菜单中陈述并且不关心如何实现处理。
代码可能如下所示:
import React, { Component } from 'react'
import onClickOutside from 'react-onclickoutside'
class Dropdown extends Component {
constructor() {
this.state = {open: false}
}
// Method automatically executed by the library.
handleClickOutside() {
this.setState({open: false})
}
render() { ... }
}
export default onClickOutside(Dropdown)
答案 2 :(得分:0)
首先,我们以open值为false创建状态,因此默认情况下关闭下拉列表。然后,我们将为单击添加一个事件侦听器,该事件侦听器将关闭下拉列表,并在关闭下拉列表后删除事件侦听器。然后,我们向按钮添加一个onClick事件,以使用toggleOpen()将状态从false更改为true。然后,我们将内容包装在if / or中,以检查其内容是否打开:
`class Dropdown extends React.Component {
constructor() {
super();
this.state = {
open: false
}
this.toggleOpen = this.toggleOpen.bind(this);
this.toggleClosed = this.toggleClosed.bind(this);
}
toggleOpen() {
this.setState({ open: true }, () => {
document.addEventListener('click', this.toggleClosed)
})
}
toggleClosed() {
this.setState({ open: false}, () => {
document.removeEventListener('click', this.toggleClosed)
})
}
render() {
return(
<div>
<button onClick=({ this.toggleOpen })>
Dropdown
</button>
{
this.state.open
? (
<span> Dropdown</span><br /><br />
<span> content</span><br /><br />
) :
(
null
)
</div>
}
}`