Я не очень хороший программист, мне удалось перенести программу DOS в Windows, а затем из Windows в Javascript работает браузер, начиная с 2014 года. У меня есть несколько прослушивателей событий нажатия клавиш, которые запускаются на основе файла настроек .js при запуске. Я хотел бы добавить кнопки отключения и включения для включения и выключения прослушивателя, если это возможно (я знаю, что перехват Ctrl и Shift может показаться некоторым сомнительным)
if (usectrlshiftdnup) {
// Trying to get Shift key 16 to step up a graph data set which works
document.addEventListener('keydown', function (event) {
if (event.keyCode === 16) {
document.activeElement.blur();
document.getElementById("upbutton").click();
document.activeElement.blur();
}
});
// Trying to get Ctrl key 17 to step down a graph data set which works
document.addEventListener('keydown', function (event) {
if (event.keyCode === 17) {
document.activeElement.blur();
document.getElementById("dnbutton").click();
document.activeElement.blur();
}
});
Обычно я программирую методом проб и ошибок, немного прочитал о RemoveEvenListener, но решил, что на этот раз просто спрошу.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете ввести уровень абстракции для управления активными в данный момент обратными вызовами прослушивателя. Что-то вроде ListenerManager.
class ListenerManager {
listeners = [];
storeListener(typeString, callback) {
this.listeners.push([typeString, callback]);
// Note that this function also automatically "enables" the stored listener
document.addEventListener(typeString, callback);
}
enableListeners() {
this.listeners.forEach((listener) => document.addEventListener(listener[0], listener[1]));
}
disableListeners() {
this.listeners.forEach((listener) => document.removeEventListener(listener[0], listener[1]));
}
}
Вы бы использовали это так:
let manager = new ListenerManager();
manager.storeListener("keydown", myCallback1);
manager.storeListener("keydown", myCallback2);
// Let's say you want to disable them all
manager.disableListeners();
// Later you want to enable them all again
manager.enableListeners();
В качестве альтернативы вы можете сделать это на более высоком уровне, что может быть проще, хотя и менее эффективно. Просто используйте глобальную логическую переменную, которую все соответствующие обратные вызовы вручную проверяют, чтобы определить, следует ли им игнорировать ввод.
let isEventsDisabled = false;
// Your callbacks would look something like:
function myCallback1(event) {
// Guard clauses
if (isEventsDisabled) return; // Relevant callbacks have this added for "disabling"
if (event.keyCode !== 16) return;
document.activeElement.blur();
document.getElementById("upbutton").click();
document.activeElement.blur();
}
// And you would register listeners "directly" the same way you have been doing
document.addEventListener("keydown", myCallback1);
// Let's say you want to disable them all
isEventsDisabled = true;
// Later you want to enable them all again
isEventsDisabled = false;
Я в значительной степени понимаю ваш первый пример и ваш второй. Я подумал, что мне следует дать функциям параметров событий дискретные имена, такие как myCallback1 и myCallback2. (событие1 и событие2)
Третий необязательный параметр, если он передан как логическое значение, просто меняет способ срабатывания события (перехват события; вы можете прочитать больше здесь, но он не имеет особого отношения к вашему варианту использования, и его можно безопасно не указывать).
Хорошо, что если вы добавили с помощью true, вы также удалили с помощью true, но проблема, возможно, заключалась в копировании вашего обратного вызова — в конечном итоге вы создаете две отдельные лямбды, которые делают одно и то же. Важно отметить, что это не один и тот же объект функции, поэтому попытка удаления не приводит к удалению первоначально добавленной функции. Да, вам следует дать каждому обратному вызову имя, чтобы позже его можно было правильно удалить.
Глобальная логическая переменная во втором примере — это просто то, что вы можете придумать как программист (она не является частью какого-либо API). Думайте об этом как об ответе на вопрос: «Должен ли я игнорировать входные данные прямо сейчас?». Поэтому по умолчанию мы устанавливаем ответ false. Всякий раз, когда мы хотим игнорировать входные данные, мы устанавливаем для него значение true. Но чтобы использовать этот ответ, нам нужно действительно задать вопрос. Где мы это спрашиваем? Во всех ваших обратных вызовах. Таким образом, каждый обратный вызов проверяет логическую переменную с помощью оператора if, чтобы «задать» вопрос. Если он должен игнорировать, не продолжайте; если его не следует игнорировать, действуйте как обычно.
Хорошо, спасибо, Облако!
Облако, работает как шарм! И Элегантный! Как программист-любитель, я очень завидую таким людям, как вы. Мне пришлось поставить var Listeners = []; над объявлением класса, поскольку консоль пинала Listeners.push как слушатели неопределенные. На самом деле, я был профессиональным пианистом в течение 50 лет и совершил ошибку, написав в 1990 году графическую программу анализа фортепианных струн (клипер с графической библиотекой), портированную на Windows в 1996 году и, наконец, портированную на javascript/браузер в 2014 году с использованием AMCharts. Поддерживаю программу для мастеров по ремонту фортепиано с самого первого дня. Огромное вам спасибо!!! На этот раз поленился.
Рад помочь. Интересная история. Я думаю, неопределённую ошибку можно исправить, используя this.listeners внутри методов класса — опечатка с моей стороны. Я отредактирую ответ соответственно. Тогда вам не придется ставить var listeners вне самого класса. Если у вас где-то хранится исходный код, мне было бы любопытно взглянуть.
Это устарело. Теперь есть AbortController, его намного проще использовать, см. stackoverflow.com/questions/68967007/…
Да, добавив это. to Listeners.push позволяет объявить массив внутри класса. Все работает так, как вы предложили и исправили. У меня нигде не опубликован исходный код (работает локально). Однако концепция переноса отдельного приложения Windows на JavaScript/браузер делает приложение кроссплатформенным, и я подозреваю, что может быть много ситуаций, когда это может быть применимо в положительном смысле. Я попробую запустить его с помощью onFocus() и onBlur() внутри текстового поля и текстовой области. Единственный другой вопрос может заключаться в отключении только одного из того, что есть в массиве, например, прослушивателя [0]. Я думаю, как-нибудь поп и толкнуть.
А, так вот почему вы отключите слушателей, я полагаю, за то, что они печатают. А необходимость индивидуального отключения объясняет добавление нескольких отдельных прослушивателей для одного и того же события. Если у вас не так много слушателей и вам необходимо индивидуальное отключение, то может быть проще просто отказаться от менеджера и написать несколько удобных функций, каждая из которых добавляет/удаляет один из именованных обратных вызовов. Например, enableShift(), disableShift(), enableControl(), disableControl() и т. д. Пока передаваемые вами обратные вызовы не дублируются, это будет работать.
Спасибо, Облако! У меня есть 8 прослушивателей клавиш Ctrl/Shift, F1/F2, [/], которые все повышают или поднимают ноту на графике, чтобы показать/редактировать данные струнного масштаба. Esc, чтобы очистить данные в сетке данных, и F9, чтобы заново построить график. Большинство из них включается или выключается в редактируемом установочном файле. Все данные представляют собой числа, за исключением файла заметок с информацией о фортепиано, поэтому отключите Shift/Ctrl для прописных букв и вставьте. Ваше решение позаботится о том, что мне нужно. Legacy использует пропущенный тип, и я еще не нашел решения для этого, поэтому Esc для пустых полей. Еще раз спасибо. Я новичок в Stack Overflow, но с момента перехода на JavaScript это много раз помогало.
Спасибо. Я попробую поработать с этими предложениями. Я пытался добавить третий параметр, правда); в addEventListener, а затем вызывая RemoveEventListener также с третьим параметром, true); но это не сработало и не выдало никаких ошибок консоли.