React中使用beautiful-dnd时双击选中文本失效,如何兼顾拖拽与选中文本?
解决方案
问题出在两个核心点:
- 样式里硬设置了
userSelect: "none",直接禁止了文本选中行为 - 把
dragHandleProps绑定在了整个文本容器上,导致整个区域都被标记为拖拽触发区,鼠标事件被拖拽逻辑拦截
下面是两种可行的修复方式:
方案一:使用独立拖拽手柄(推荐)
将拖拽触发区域和文本区域分离,只给特定元素绑定拖拽手柄,文本区域保留默认的选中交互:
const getItemStyle = (isDragging, draggableStyle) => ({ margin: `0 0 ${grid}px 0`, padding: "24px 16px 24px 16px", background: isDragging ? "lightgreen" : "unset", display: "flex", alignItems: "center", gap: "16px", ...draggableStyle, }); const getListStyle = (isDraggingOver) => ({ background: isDraggingOver ? "lightblue" : "#f9f9f9", padding: grid, width: "100%", }); <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="droppable"> {(provided, snapshot) => ( <div {...provided.droppableProps} ref={provided.innerRef} style={getListStyle(snapshot.isDraggingOver)} > {items.map((item, index) => ( <Draggable key={item.draggableId} draggableId={item.draggableId} index={index} > {(provided, snapshot) => ( <div key={item.id} ref={provided.innerRef} {...provided.draggableProps} style={getItemStyle( snapshot.isDragging, provided.draggableProps.style )} > {/* 单独的拖拽手柄 */} <div {...provided.dragHandleProps} style={{cursor: "grab"}}> ☰ </div> {/* 文本区域,默认支持选中 */} <div style={{flex: 1, userSelect: "text"}}> This is my text </div> </div> )} </Draggable> ))} {provided.placeholder} </div> )} </Droppable> </DragDropContext>
方案二:保留整个区域可拖拽,修复双击选中文本
如果需要整个区域都能触发拖拽,同时支持双击选中文本,可以通过样式调整和事件处理实现:
const getItemStyle = (isDragging, draggableStyle) => ({ margin: `0 0 ${grid}px 0`, padding: "24px 16px 24px 16px", background: isDragging ? "lightgreen" : "unset", // 仅在拖拽时禁止选中,平时允许文本选择 userSelect: isDragging ? "none" : "text", ...draggableStyle, }); const getListStyle = (isDraggingOver) => ({ background: isDraggingOver ? "lightblue" : "#f9f9f9", padding: grid, width: "100%", }); const handleDoubleClick = (e) => { // 阻止拖拽逻辑拦截双击事件 e.stopPropagation(); // 手动选中文本内容 const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(e.currentTarget); selection.removeAllRanges(); selection.addRange(range); }; <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="droppable"> {(provided, snapshot) => ( <div {...provided.droppableProps} ref={provided.innerRef} style={getListStyle(snapshot.isDraggingOver)} > {items.map((item, index) => ( <Draggable key={item.draggableId} draggableId={item.draggableId} index={index} > {(provided, snapshot) => ( <div key={item.id} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={getItemStyle( snapshot.isDragging, provided.draggableProps.style )} onDoubleClick={handleDoubleClick} > This is my text </div> )} </Draggable> ))} {provided.placeholder} </div> )} </Droppable> </DragDropContext>
关键说明
- 方案一的用户体验更清晰,能明确区分拖拽触发区和文本操作区,减少误操作
- 方案二中,
userSelect的条件设置避免了拖拽时意外选中文本,双击时通过stopPropagation阻断拖拽逻辑的干扰,再手动完成文本选中
内容的提问来源于stack exchange,提问作者Rana Faraz
相关产品推荐
相关产品推荐

