javascript - 反应:下拉菜单没有在外面的水龙头上关闭
问题描述
我有以下代码用于为某些项目创建下拉列表:
import React, { Component } from "react"
import { connectRefinementList } from "react-instantsearch-dom"
import PropTypes from "prop-types"
const cx = label => `ais-DropdownRefinementList-${label}`
class DropdownRefinementList extends Component {
constructor(props) {
super(props)
this.state = {
active: false,
mobile: false,
}
}
componentDidMount() {
this.setState({
mobile: /Mobi/.test(navigator.userAgent),
})
}
capitalizeFirst(s) {
return s.charAt(0).toUpperCase() + s.slice(1)
}
renderItem = (item, i) => (
<label key={i} className="ais-DropdownRefinementList-item-label">
<input
type="checkbox"
checked={item.isRefined}
onChange={() => {
this.selectItem(item)
}}
/>
<span>{item.label}</span>
<span className={cx("item-count")}> ({item.count})</span>
</label>
)
selectItem = (item, resetQuery) => {
this.props.refine(item.value)
}
handleEvent = e => {
this.setState({ active: !this.state.active })
}
render() {
const { items, attribute, hoverable, currentRefinement, icon } = this.props
const { active, mobile } = this.state
const title = this.capitalizeFirst(attribute)
console.log(this.state)
return (
<div
className={`ais-DropdownRefinementList-container-${attribute}`}
onMouseLeave={hoverable && !mobile && this.handleEvent}
onMouseEnter={hoverable && !mobile && this.handleEvent}
>
<div className={cx("title-container")} onClick={this.handleEvent}>
<span class="w-full focus:text-teal-500 hover:text-teal-500 justify-center inline-block text-gray-600 text-xl text-center ">
{icon}
</span>
<span className="ais-DropdownRefinementList-title font-bold w-full text-gray-600">
{title}{" "}
</span>
</div>
{active && (
<div className={`ais-DropdownRefinementList-List ${attribute}`}>
{items.map(this.renderItem)}
</div>
)}
</div>
)
}
}
DropdownRefinementList.propTypes = {
attribute: PropTypes.string.isRequired,
icon: PropTypes.string.isRequired,
hoverable: PropTypes.bool,
limit: PropTypes.number,
}
DropdownRefinementList.defaultProps = {
hoverable: false,
}
export default connectRefinementList(DropdownRefinementList)
在笔记本电脑上,这些工作正常,当我将鼠标悬停在列表标题上时,下拉菜单打开,当我离开时,下拉菜单关闭。我曾认为当我在移动设备上时也会发生同样的情况。然而,这种情况并非如此。当用户单击另一个下拉菜单时,一个下拉菜单将保持打开状态。如下所示:
尽管有onMouseLeave
和的条件onMouseEnter
。这不适用于移动设备吗?容器外的水龙头不应该再次隐藏它吗,就像它应该的那样?
我怎样才能使这项工作也适用于手机?
如果有帮助,这是该组件的 CSS,这是一个实时部署(您必须使用 Inspect Element 切换到移动视图,因为它隐藏在大屏幕上)。
解决方案
我查看了一些有关如何在移动设备上翻译鼠标事件的文档:https ://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent
我的建议是不要在移动设备上依赖 mouseenter 和 mouseleave。我会激活一个道具,让父母跟踪哪些 DropdownRefinementLists 应该是可见的。那是因为 DropdownRefinementList 看不到外面的点击事件。我将处理接收外部空间事件的祖先中的“外部点击”事件。
示例代码:
这是(新)DropdownRefinementList
。this.props.active
是真还是假,取决于它是否应该显示弹出窗口。this.props.setActive()
它在收到点击/触摸时调用。
class DropdownRefinementList extends React.Component {
constructor(props) {
super(props)
}
handleEvent = e => {
this.props.setActive();
e.stopPropagation(); //stop event from propagating to ancestor elements
}
render() {
return (
<div onClick={this.handleEvent} style={{position: 'relative', padding: '5px'}}>
<h3>
{this.props.title}
</h3>
<div style={{marginTop: '1rem'}}>
Click me!
</div>
{this.props.active && (
<div style={{
position: 'absolute',
top: '-50px', left: '25px',
height: '150px', width: '200px',
borderStyle: 'solid',
backgroundColor: '#ccc',
padding: '5px',
zIndex: 100
}}>
{this.props.title}{' '} Popup
</div>
)}
</div>
)
}
}
这是父组件。this.state.activeDropdown
采用以下 3 个值:
- 0:没有下拉菜单处于活动状态
- 1:下拉菜单 1 处于活动状态
- 2:下拉菜单 2 处于活动状态
this.state.activeDropdown
当它收到点击/触摸时,它设置为 0。
class DropdownRefinementListParent extends React.Component {
constructor(props) {
super(props)
this.state = {
activeDropdown: 0
}
}
setActive = (whichDropdown) => {
this.setState({activeDropdown: whichDropdown});
}
handleEvent = (e, whichDropdown) => {
this.setActive(0);
e.stopPropagation(); //stop event from propagating to ancestor elements
}
render() {
const dropdown1IsActive = (this.state.activeDropdown === 1);
const dropdown2IsActive = (this.state.activeDropdown === 2);
return (
<div onClick={e => this.handleEvent(e, 0)}>
<h2>DropdownRefinementList Parent</h2>
<div>activeDropdown: {this.state.activeDropdown}</div>
<div style={{display: 'flex', margin: '10px 0', width: '600px', justifyContent: 'flex-start'}}>
<div style={{flexGrow: 0, borderStyle: 'solid', margin: '5px'}}>
<DropdownRefinementList
title="DropdownRefinementList 1"
active={dropdown1IsActive}
setActive={() => this.setActive(1)} />
</div>
<div style={{flexGrow: 0, borderStyle: 'solid', margin: '5px'}}>
<DropdownRefinementList
title="DropdownRefinementList 2"
active={dropdown2IsActive}
setActive={() => this.setActive(2)} />
</div>
</div>
end
</div>
)
}
}
推荐阅读
- python - Python 3 策略/工厂模式:动态继承一种或多种抽象类类型实现的类实例类型
- c# - 用于创建表达式的 PredicateBuilder 辅助函数
- python - Flask mail Python:在邮件正文中添加换行符
- machine-learning - 'predict_generator' 返回大于 1 且小于 0 的值
- c++ - 某些代码未从代码覆盖范围中删除
- mysql - 如何从 MySQL 中的日期获取该年的当前周数?
- callback - 异步调用不适用于代码中的 Callback()
- c# - 如何将 Azure 函数输入参数绑定到存储帐户?
- javascript - 将高阶 Observable 合并到现有对象中
- c# - 列表
调试模式下的声明速度差异