问题描述
当我们使用拖拽库的时候,往往会遇到拖拽的一个元素他的子孙元素有输入框类型的dom节点,当拖拽的事件绑定在该元素身上时候,发现子孙的输入框不能进行文本选中了,会按住鼠标去选中文本的时候会触发拖拽
实际的效果,鼠标无法选中文本输入框中的值
解决1:拖拽事件绑定到子孙元素
不再将绑定事件绑到整个dom,使用拖拽句柄,在拖拽库中一般都有句柄的选项,可以把拖拽的事件绑定子孙的某个节点上,一般拖拽可以绑定 className='handle'
的节点去
每个库都有自己的写法,搜索一下即可
下面以react-draggable
库为例子
js
import Draggable from 'react-draggable';
function Component() {
return (
<Draggable handle=".handle">
<div>
<div className="handle"> Drag </div>
<div> Content ...</div>
</div>
</Draggable>
);
}
解决2:保持拖拽绑定,处理事件冲突
原理是在拖拽的事件中,判断当前触发拖拽事件的节点是否是 input框,如果是就阻止拖拽事件,自然就可以就行选择文本的操作了,
下面以reac-dnd
库为例:
在useDrag
方法中canDrag
方法中可以进行判断,返回一个false就可以阻止拖动,核心的判断是使用document.activeElement.tagName
获取当前的激活事件的Dom节点的相关信息进行判断,相关的知识可以百度一下
js
//下面只展示核心部分
import { DndProvider, useDrag, useDrop } from 'react-dnd';
const DragDom= () => {
const [{ isDragging }, drag] = useDrag(() => ({
type: 'aaa',
canDrag: (m) => {
if(document.activeElement.tagName === 'INPUT') return false
return true
},
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}));
return (
<div ref={drag}> Drag </div>
);
};
最后大功告成
2024.12.23 更新
if(document.activeElement.tagName === 'INPUT') return false
这个判断改造了 改为下面的数组形式,需要什么类型的元素不被拖动就往数组里面加
js
if(['INPUT', 'TEXTAREA'].some(i => i===document.activeElement.tagName)) return false
引申思考:
我们可以把不需要拖拽的元素写入某个特定的类名, 这不管元素如何布局都可以控制不拖动
下面是用于判断拖拽的伪代码
js
<div>
<div >元素1<div>
<div class='不允许拖拽类名'>不可以动元素2<div>
<div >元素3<div>
</div>
useDrag(() => ({
canDrag: () => {
if(document.activeElement的类名 === '不允许拖拽类名') return false
return true
}
}))