我正在尝试制作具有2个可拖动手柄的范围滑块。它仍处于早期阶段,此时,我试图使两个手柄在拖动时独立移动。
但是,我遇到的问题是,如果将事件处理程序绑定到document
,则在拖动一个事件时两个句柄会一起移动。如果我绑定到通过选择器参数传入的元素(句柄本身),则两个句柄都将独立移动,但只有当鼠标指针位于该元素的范围内时才能起作用,这不是很好的行为。
这是我的代码。我在做什么错了?
function draggable(selector, options) {
var options = options || {};
let el = document.querySelector(selector);
var mx = 0,
my = 0;
var dragging = false;
var offset = [0, 0];
var constrain = options.constrain || false;
if (options === undefined) options = [];
document.addEventListener('mousedown', function(e) {
dragging = true;
offset = {
x: el.offsetLeft - e.clientX,
y: el.offsetTop - e.clientY
};
});
document.addEventListener('mousemove', function(e) {
e.preventDefault();
mx = e.clientX;
my = e.clientY;
if (dragging) {
if (!constrain || constrain == 'x') el.style.left = (mx + offset.x) + 'px';
if (!constrain || constrain == 'y') el.style.top = (my + offset.y) + 'px';
}
});
document.addEventListener('mouseup', function(e) {
dragging = false;
});
}
var min = new draggable('#min', {
constrain: 'x'
});
var max = new draggable('#max', {
constrain: 'x'
});
body {
padding: 50px;
}
.range-input {
height: 24px;
position: relative;
}
.rail {
background: rgba(0, 0, 0, 0.5);
border-radius: 9px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0);
height: 9px;
width: 100%;
}
.handle {
background: #000;
border-radius: 50%;
height: 24px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
width: 24px;
}
.handle:hover {
cursor: grab;
transform: translate3d(0, -50%, 0) scale(1.2);
}
.handle:active {
cursor: grabbing;
}
.min {
left: 0;
}
.max {
right: 0;
}
<div id="wrap" class="range-input">
<div class="rail"></div>
<div id="min" class="handle min"></div>
<div id="max" class="handle max"></div>
</div>
答案 0 :(得分:2)
两个元素都注册了一个事件处理程序,该事件处理程序正在侦听文档上的拖动事件。您的逻辑不包含任何排除项,因此,只要在窗口中的任意位置单击并拖动动作,就会触发您的逻辑。
不过,我可以看到您要阻止的事情。我想您要确保在拖动动作(向上或向下)期间鼠标离开手柄时,拖动动作会继续触发。为此,在元素上注册mousedown事件。您仍然可以在文档中注册拖动事件,但是将它们移到事件处理程序中以进行鼠标按下,如下所示:
function draggable(selector, options) {
var options = options || {};
let el = document.querySelector(selector);
var mx = 0,
my = 0;
var dragging = false;
var offset = [0, 0];
var constrain = options.constrain || false;
if (options === undefined) options = [];
el.addEventListener('mousedown', function(e) {
dragging = true;
offset = {
x: el.offsetLeft - e.clientX,
y: el.offsetTop - e.clientY
};
document.addEventListener('mousemove', function(e) {
e.preventDefault();
mx = e.clientX;
my = e.clientY;
if (dragging) {
if (!constrain || constrain == 'x') el.style.left = (mx + offset.x) + 'px';
if (!constrain || constrain == 'y') el.style.top = (my + offset.y) + 'px';
}
});
document.addEventListener('mouseup', function(e) {
dragging = false;
});
});
}
var min = new draggable('#min', {
constrain: 'x'
});
var max = new draggable('#max', {
constrain: 'x'
});
body {
padding: 50px;
}
.range-input {
height: 24px;
position: relative;
}
.rail {
background: rgba(0, 0, 0, 0.5);
border-radius: 9px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0);
height: 9px;
width: 100%;
}
.handle {
background: #000;
border-radius: 50%;
height: 24px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
width: 24px;
}
.handle:hover {
cursor: grab;
transform: translate3d(0, -50%, 0) scale(1.2);
}
.handle:active {
cursor: grabbing;
}
.min {
left: 0;
}
.max {
right: 0;
}
<div id="wrap" class="range-input">
<div class="rail"></div>
<div id="min" class="handle min"></div>
<div id="max" class="handle max"></div>
</div>
请注意,完成拖动操作后,您将需要注销文档事件处理程序。我没有添加该逻辑,但这并不难。
答案 1 :(得分:2)
仅对于mousedown
,应检查被单击元素是否确实是您想要的元素
function draggable(selector, options) {
var options = options || {};
let el = document.querySelector(selector);
var mx = 0,
my = 0;
var dragging = false;
var offset = [0, 0];
var constrain = options.constrain || false;
if (options === undefined) options = [];
el.addEventListener('mousedown', function(e) {
dragging = true;
offset = {
x: el.offsetLeft - e.clientX,
y: el.offsetTop - e.clientY
};
});
document.addEventListener('mousemove', function(e) {
e.preventDefault();
mx = e.clientX;
my = e.clientY;
if (dragging) {
if (!constrain || constrain == 'x') el.style.left = (mx + offset.x) + 'px';
if (!constrain || constrain == 'y') el.style.top = (my + offset.y) + 'px';
}
});
document.addEventListener('mouseup', function(e) {
dragging = false;
});
}
var min = new draggable('#min', {
constrain: 'x'
});
var max = new draggable('#max', {
constrain: 'x'
});
body {
padding: 50px;
}
.range-input {
height: 24px;
position: relative;
}
.rail {
background: rgba(0, 0, 0, 0.5);
border-radius: 9px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0);
height: 9px;
width: 100%;
}
.handle {
background: #000;
border-radius: 50%;
height: 24px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
width: 24px;
}
.handle:hover {
cursor: grab;
transform: translate3d(0, -50%, 0) scale(1.2);
}
.handle:active {
cursor: grabbing;
}
.min {
left: 0;
}
.max {
right: 0;
}
<div id="wrap" class="range-input">
<div class="rail"></div>
<div id="min" class="handle min"></div>
<div id="max" class="handle max"></div>
</div>
答案 2 :(得分:0)
这是一种解决方案,可获取更大的区域来拖动div元素。我创建了一个container
类的背景div,该背景div大于要拖动和透明的div
.container {
width: 48px;
height: 48px;
border-radius: 50%;
background: transparent;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
}
function draggable(selector, options) {
var options = options || {};
let el = document.querySelector(selector);
var mx = 0,
my = 0;
var dragging = false;
var offset = [0, 0];
var constrain = options.constrain || false;
if (options === undefined) options = [];
el.addEventListener('mousedown', function(e) {
dragging = true;
offset = {
x: el.offsetLeft - e.clientX,
y: el.offsetTop - e.clientY
};
});
document.addEventListener('mousemove', function(e) {
e.preventDefault();
mx = e.clientX;
my = e.clientY;
if (dragging) {
if (!constrain || constrain == 'x') el.style.left = (mx + offset.x) + 'px';
if (!constrain || constrain == 'y') el.style.top = (my + offset.y) + 'px';
}
});
document.addEventListener('mouseup', function(e) {
dragging = false;
});
}
var min = new draggable('#min', {
constrain: 'x'
});
var max = new draggable('#max', {
constrain: 'x'
});
body {
padding: 50px;
}
.range-input {
height: 24px;
position: relative;
}
.rail {
background: rgba(0, 0, 0, 0.5);
border-radius: 9px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0);
height: 9px;
width: 100%;
}
.container {
width: 48px;
height: 48px;
border-radius: 50%;
background: transparent;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
}
.handle {
background: #000;
border-radius: 50%;
height: 24px;
position: absolute;
top: 50%;
transform: translate3d(0, -50%, 0) scale(1);
width: 24px;
}
.container:hover {
cursor: grab;
transform: translate3d(0, -50%, 0) scale(1.2);
}
.container:active {
cursor: grabbing;
}
.min {
left: 0;
}
.max {
right: 0;
}
<div id="wrap" class="range-input">
<div class="rail"></div>
<div id="min" class="container min">
<div class="handle min"></div>
</div>
<div id="max" class="container max">
<div class="handle max"></div>
</div>
</div>