Обработка клика, двойного клика и перетаскивания по одному и тому же элементу
мне привели пример кода из другого вопроса, но почему то он не совсем корректно работает на мой взгляд:
$(function() {
var doubleClickThreshold = 250;
var lastClick = 0;
var isDragging;
var isDoubleClick = false;
var mouseIsDown = false;
$control = $("#controler");
$control.click(function(){
var thisClick = new Date().getTime();
isDoubleClick = thisClick - lastClick < doubleClickThreshold; console.log(2);
lastClick = thisClick;
});
$control.mousedown(function() {
mouseIsDown = true;
});
$control.mouseup(function() {
isDragging = false;
mouseIsDown = false;
});
$(document).mousemove(function() {
if (mouseIsDown) {
isDragging = true;
}
});
if (isDoubleClick) {
console.log(1);
}
});
дело в том что - при двойном допустим клике - мне выводит сообщение console.log(2); т.е. конструкция $control.click(function(){ - работает и если там выводить переменную console.log(isDoubleClick) то она показывать false true false true - т.е. определяется, но в самом конце где идет
if (isDoubleClick) {
console.log(1);
}
она почему то постоянно false - не выводится мой чек console.log(1);
подскажите пожалуйста что не так? это какая то локальная видимость переменных?
по тому что в конце мне бы хотелось сделать такую конструкцию:
if (isDoubleClick) {
//действия для двойного клика
} else if (isDragging) {
//действия для перетаскивания
} else {
//действия одинарного клика
}
Ответы (3 шт):
Приведенная ниже конструкция, к которой вы хотите прийти по сути является блоками исполняемого кода на определенное событие. В программистском народе это блоки называют функциями коллбеками (callbacks). Это такой шаблон асинхронного исполнения кода.
Не совсем понятно, почему вы разные коллбеки хотите проверять на if else.
Я уже частично ответил на ваш вопрос, почему вы никогда не увидите в консоли 1. Вы инициализируете переменную isDoubleClick значением false и исполняете блок кода
if (isDoubleClick) {
console.log(1);
}
единожды, когда скрипт загрузился и может быть исполнен (то есть синхронно/сейчас). А код слушателей событий, в котором isDoubleClick изменит свое значение, выполнится асинхронно (потом).
Возвращаясь к тому коду, что я вам скинул ранее в комментарии. Он работает таким образом, что вы определите двойной клик. Однако первый клик тоже отработает как событие.
Поэтому я написал немного другую структуру, которая будет четко генерировать нужное вам событие.
const doubleClickThreshold = 250;
const clicker = document.getElementById('clicker');
const output = document.getElementById('output');
function createClicker(clickFn, dblClickFn) {
let timer;
return function (event) {
const context = this;
if (timer) {
clearTimeout(timer);
dblClickFn.call(context, event);
timer = null;
return;
}
timer = setTimeout(function (ctx) {
timer = null;
clickFn.call(ctx, event);
}, doubleClickThreshold, context)
}
}
function onClick(event) {
output.innerHTML = 'click';
}
function onDoubleClick(event) {
output.innerHTML = 'double click';
}
const clickHandler = createClicker(onClick, onDoubleClick);
clicker.onclick = clickHandler;
<button id="clicker">Click</button>
<div>Сработал: <span id="output"></span></div>
В функцию createClicker надо передать две функции, одна вызовется на одинарный клик, вторая на двойной. Это заменит вашу if else конструкцию.
Этот способ тоже имеет определенный недостаток: событие одинарного клика будет иметь лаг в 250ms (doubleClickThreshold). Это то время, в течение которого мы ждем второй клик. И если его нет, то вызываем функцию клика.
Значение этого лага можно уменьшить. Тогда двойной клик надо будет осуществлять быстрее. В общем, найдите нужный вам баланс.
Для отслеживание двойного клика можно использовать событие dblclick, а для перетягивания события: drag, dragend, dragover, dragleave, dragstart, dragenter, drop. Все эти события можно найти в глобальном объекте window.
Как я понял, вам надо было разделить все эти евенты, при двойном клике не должно было срабатывать событие клика и аналогично и для перемещения элемента? Вроде бы получилось как раз то, что вам было нужно:
function makeEvent (elem, {onClick, onDblClick, onDrag}) {
if (elem) {
let timer;
let pushme = false;
let dragable = false;
const el = document.querySelector(elem);
el.onmouseup = () => pushme = false;
el.onmousedown = () => pushme = true;
el.onclick = (e) => {
if (!dragable) {
timer = setTimeout(function () {
if (timer) {
onClick.call(e.target, e);
}
}, 250);
}
dragable = false;
}
el.ondblclick = (e) => {
e.preventDefault();
clearTimeout(timer);
timer = null;
onDblClick.call(e.target, e);
}
el.onmousemove = (e) => {
e.preventDefault();
if (pushme) {
dragable = true;
onDrag.call(e.target, e);
if (timer) {
clearTimeout(timer);
timer = null;
}
}
}
}
}
// Использование
makeEvent('.btn', {
onClick: function () {
alert('click');
},
onDblClick: function () {
alert('double click');
},
onDrag: function (e) {
this.style.top = (e.pageY - (this.offsetHeight / 2)) + 'px';
this.style.left = (e.pageX - (this.offsetWidth / 2)) + 'px';
}
})
.btn {
position:absolute;
right:10px;
display:inline-block;
width:100px;
padding:10px;
text-align:center;
background:#c54654;
cursor:pointer;
color:#fff;
}
<div class="btn" dragtable>click</div>