react-grid-layout点击元素触发拖拽而非点击事件问题求助
React-Grid-Layout 点击元素触发拖拽而非onClick事件的解决方案
在使用react-grid-layout组件构建包含可点击、可拖拽元素的网格时,遇到点击元素无需移动光标就直接触发拖拽功能,无法触发div上绑定的onClick事件的问题。相关实现代码如下:
Render方法代码
render() { return ( <div className="gridL" style={{minHeight: '65px'}}> <StarIcon style={{ position: 'absolute', fontSize: 26, marginTop: 20, marginLeft: '5px', color: 'orange'}} /> {this.props.favoritesData == null || this.props.favoritesData.length == 0 && ( <div style={{ position: 'absolute', marginLeft: '35px', marginTop: '24px', height: '30px', color: 'gray'}}> Comece a adicionar favoritos para facilitar o acesso aos seus sistemas. <img alt="hehehe" width={10} src="https://rastreio.grupoleonora.com.br/favicon.ico" /> </div> )} <ResponsiveReactGridLayout {...this.props} layouts={this.state.layouts} cols={{ xl: 22, lg: 20, md: 16, sm: 12, xs: 8, xxs: 6 }} breakpoints={{ xl: 1400, lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }} rowHeight={50} isBounded={false} onDrag={this.onDrag} onDragStop={this.onDragStop} onLayoutChange={this.onLayoutChange} className="favorites-grid-layout" onBreakpointChange={this.onBreakpointChange} onDrop={this.onDrop} maxRows={1} verticalCompact={true} measureBeforeMount={false} isResizable={false} useCSSTransforms={true} compactType="horizontal" preventCollision={this.state.mounted} isDroppable={true} isDraggable={true} style={{ marginLeft: 25, minHeight: 55 }} > {Array.isArray(this.state.layouts[this.state.currentBreakpoint]) ? this.generateDOM(this.state.layouts[this.state.currentBreakpoint]) : null} </ResponsiveReactGridLayout> </div> ); }
generateDOM方法代码
generateDOM(layouts: any) { return layouts.map((el: any) => { const moduleId = this.props.modulesData?.find(q => q.id.toString() === el.i)?.id || -1; const isContextMenuOpen = this.state.contextMenus?.find(c => c.index?.toString() === el.i)?.index !== undefined && this.state.contextMenus?.find(c => c.index?.toString() === el.i)?.index !== null; return ( <div key={el.i} data-grid={el} onClick={() => !this.state.isDragging && !isContextMenuOpen && this.openFavorite(this.props.modulesData?.find(q => q.id.toString() === el.i)?.url)} onContextMenu={(e: any) => this.handleContextMenu(this.props.modulesData?.find(q => q.id.toString() === el.i)?.id || -1, e)} style={{ cursor: 'pointer' }} > <CardLinkFavoriteDisabled image={this.props.modulesData?.find(q => q.id.toString() === el.i)?.imageNavigation.filename} title={this.props.modulesData?.find(q => q.id.toString() === el.i)?.name} /> <Menu PaperProps={{ sx: { boxShadow: '0px 2px 10px 0px rgba(58, 53, 65, 0.1) !important', backgroundImage: 'linear-gradient(98deg, rgba(10,12,71,0.9), rgba(59,240,58,0.9) 160%)' }, }} open={isContextMenuOpen} onClose={() => this.handleClose(moduleId)} anchorReference="anchorPosition" anchorPosition={ this.props.modulesData?.find(q => q.id.toString() === el.i) !== null ? { top: this.state.contextMenus?.find(c => c.index === moduleId)?.mouseY || 0, left: this.state.contextMenus?.find(c => c.index === moduleId)?.mouseX || 0 } : undefined } elevation={0} componentsProps={{ root: { onContextMenu: (e) => { e.preventDefault(); this.handleClose(moduleId); }, }, }} > <MenuItem style={{ fontSize: 12, height: 15, color: 'white' }} onClick={(e) => { this.RemoveFavorite(e, moduleId) }}> <DeleteIcon color="error" /> Remover </MenuItem> </Menu> </div> ); }); }
解决方案
react-grid-layout的拖拽逻辑会监听元素的mousedown事件,默认优先级高于点击事件,可通过以下三种方式解决:
方式1:指定拖拽触发区域
将拖拽触发限制在特定手柄区域,而非整个元素,点击元素其他区域时触发onClick:
- 修改generateDOM中的元素结构,添加拖拽手柄:
return ( <div key={el.i} data-grid={el} onClick={() => !this.state.isDragging && !isContextMenuOpen && this.openFavorite(this.props.modulesData?.find(q => q.id.toString() === el.i)?.url)} onContextMenu={(e: any) => this.handleContextMenu(this.props.modulesData?.find(q => q.id.toString() === el.i)?.id || -1, e)} style={{ cursor: 'pointer', position: 'relative' }} > {/* 拖拽手柄区域 */} <div className="drag-handle" style={{ position: 'absolute', top: 0, right: 0, width: '20px', height: '100%', cursor: 'grab' }} /> <CardLinkFavoriteDisabled image={this.props.modulesData?.find(q => q.id.toString() === el.i)?.imageNavigation.filename} title={this.props.modulesData?.find(q => q.id.toString() === el.i)?.name} /> {/* 菜单代码保持不变 */} </div> );
- 在ResponsiveReactGridLayout组件中添加
draggableHandle属性,指定拖拽触发选择器:
<ResponsiveReactGridLayout // 其他属性保持不变 draggableHandle=".drag-handle" > {/* 子元素 */} </ResponsiveReactGridLayout>
方式2:设置拖拽触发阈值+状态判断
通过组件配置和状态控制,只有鼠标移动超过一定距离才触发拖拽:
- 添加拖拽状态控制方法:
onDragStart = () => { this.setState({ isDragging: true }); }; onDragStop = () => { setTimeout(() => { this.setState({ isDragging: false }); }, 100); };
- 在ResponsiveReactGridLayout中绑定事件并设置拖拽阈值:
<ResponsiveReactGridLayout // 其他属性保持不变 onDragStart={this.onDragStart} onDragStop={this.onDragStop} dragStartThreshold={3} // 鼠标移动3像素后才触发拖拽 > {/* 子元素 */} </ResponsiveReactGridLayout>
方式3:阻止点击区域事件冒泡
在需要触发点击的子元素上阻止mousedown事件冒泡,避免拖拽逻辑触发:
<CardLinkFavoriteDisabled image={this.props.modulesData?.find(q => q.id.toString() === el.i)?.imageNavigation.filename} title={this.props.modulesData?.find(q => q.id.toString() === el.i)?.name} onMouseDown={(e) => e.stopPropagation()} />
内容的提问来源于stack exchange,提问作者Thiago Marquezini
相关产品推荐
相关产品推荐

