Как правильно использовать делегирование событий вместо добавления второго одновременного прослушивателя событий для того же типа событий?

Я использую функцию document.addEventListener("DOMContentLoaded",() чтобы принудительно ввести шаблон ввода (сначала должна быть буква, затем не допускать последовательных пробелов и т. д.)

Теперь я хочу создать вторую функцию document.addEventListener("DOMContentLoaded",() для электронного письма. (Я хочу предотвратить несколько . и предотвратить более 1 @)

Вот мой код для обоих вышеперечисленных пунктов, но он не работает, он только пишет электронную почту с заглавной буквы (я оставил эту опцию включенной, чтобы проверить, работает ли эта часть, что она и делает, но больше ничего не работает.)

Вот первая часть (я пробовал еще кое-что, удалив первую }); в document.addEventListener("DOMContentLoaded", function () в начале второго числа, как я слышал, это должно работать, но это тоже не сработало.

document.addEventListener("DOMContentLoaded", function() {
  // Function to handle all keypress events
  function handleKeyPress(event) {
    const input = event.target;
    const char = String.fromCharCode(event.which);

    // Prevent first character from being a space
    if (input.selectionStart === 0 && event.code === "Space") {
      event.preventDefault();
      return;
    }

    // Prevent first character from being a non-letter
    if (input.selectionStart === 0 && !/^[a-zA-Z]$/.test(char)) {
      event.preventDefault();
      return;
    }

    // Prevent consecutive spaces
    const lastChar = input.value.charAt(input.selectionStart - 1);
    if (char === " " && lastChar === " ") {
      event.preventDefault();
      return;
    }
  }

  // Attach event listeners to input fields
  const inputs = document.querySelectorAll("input[name='real_name'], input[name='display_name']");
  inputs.forEach(input => {
    input.addEventListener("keypress", handleKeyPress);

    // Set text-transform to capitalize to force capitalization of each word
    input.style.textTransform = "capitalize";
  });
});
document.addEventListener("DOMContentLoaded", function() {
  // Function to handle all keypress events
  function handleKeyPress2(event) {
    const input = event.target;
    const char = String.fromCharCode(event.which);

    // Prevent first character from being a space
    if (input.selectionStart === 0 && event.code === "Space") {
      event.preventDefault();
      return;
    }

    // Prevent consecutive spaces
    const lastChar = input.value.charAt(input.selectionStart - 1);
    if (char === "@" && lastChar === "@") {
      event.preventDefault();
      return;
    }

    var key = event.keyCode || event.charCode || event.which;
    if (key == 32) {
      return false;
    } else {
      return key;
    }
  }

  // Attach event listeners to input fields
  const inputs = document.querySelectorAll("input[name='email']");
  inputs.forEach(input => {
    input.addEventListener("keydown", handleKeyPress2);

    // Set text-transform to capitalize to force capitalization of each word
    input.style.textTransform = "capitalize";
  });
});

Пожалуйста, нажмите изменить, прокрутите вниз и нажмите «изменить фрагмент выше» и добавьте соответствующие HTML, CSS и фреймворки, которые вы используете, из CDN.

mplungjan 03.09.2024 12:59

Проблема, вероятно, не в двойной привязке к событию DOMContentLoaded, а скорее в том, что вы дважды привязываетесь к событию keypress для всех этих полей - и я предполагаю, что комбинация event.preventDefault(); и return;, вероятно, не позволяет ему даже выполнить второй назначенный обработчик нажатия клавиши. . Для начала вам лучше попытаться сделать все эти вещи в одном обработчике нажатия клавиш.

C3roe 03.09.2024 13:03

1) Вам не нужно несколько обработчиков DOMContentLoaded. Вы можете поместить всю свою логику в одну. 2) Является ли поле электронной почты type = "email"? У него немного другая модель событий на основе ключей, чем у элемента type = "text", что может объяснить вашу проблему. 3) Не используйте text-transform на элементе input. Он неточно отражает то, что пользователь ввел в форму, и может вызвать путаницу. Например, они вводят foo, но видят Foo, а ваш сервер все равно получит foo, поэтому это повлияет на любые проверки на достоверность/сравнение.

Rory McCrossan 03.09.2024 13:03

Я не смог воспроизвести проблему, все работало нормально. Пожалуйста, добавьте HTML-файл. Как создать минимальный воспроизводимый пример

m-sarabi 03.09.2024 13:10

Также вам обязательно нужно посмотреть делегирование событий. Имейте ОДИН обработчик событий в ближайшем статическом контейнере для входных данных.

mplungjan 03.09.2024 13:14

1. не знаю, как все это собрать воедино. 2. type = "email" 3. нет преобразования текста

Antarctica-UFO 03.09.2024 13:21
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
6
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам не нужно подключать несколько обработчиков событий DOMContentLoaded. Вы можете связать один и поместить в него все обработчики событий для ваших HTML-элементов.

Однако причина вашей проблемы в том, что вы используете событие keydown на input из type = "email". Как вы обнаружили, это поведение несовместимо с входными данными type = "text".

Учитывая вашу цель, самым простым подходом было бы использование встроенных валидаторов HTML, поскольку это гарантирует, что всем полям будет присвоено значение при отправке, а также будет гарантировать, что поле электронной почты имеет правильный формат. Это дает дополнительное преимущество: оно работает независимо от того, включен ли в браузере пользователя Javascript.

Вот рабочий пример:

function nameInputRestrictor(event) {
  const input = event.target;
  const char = String.fromCharCode(event.which);

  // Prevent first character from being a space
  if (input.selectionStart === 0 && event.code === "Space") {
    event.preventDefault();
    return;
  }

  // Prevent first character from being a non-letter
  if (input.selectionStart === 0 && !/^[a-zA-Z]$/.test(char)) {
    event.preventDefault();
    return;
  }

  // Prevent consecutive spaces
  const lastChar = input.value.charAt(input.selectionStart - 1);
  if (char === " " && lastChar === " ") {
    event.preventDefault();
    return;
  }
}

document.addEventListener("DOMContentLoaded", function() {
  document.querySelectorAll("input[name='real_name'], input[name='display_name']").forEach(input => {
    input.addEventListener("keypress", nameInputRestrictor);
  });
});
label {
  display: block;
} 
<form>
  <label>
    Real name: <input type = "text" name = "real_name" required />
  </label>
  <label>
    Display name: <input type = "text" name = "display_name" required />
  </label>
  <label>
    Email: <input type = "email" name = "email" required />
  </label>
  
  <button type = "submit">Submit</button>
</form>

Также обратите внимание, что использование text-transform в элементе input — крайне плохая практика. Это связано с тем, что тогда поле не будет точно соответствовать тому, что ввел пользователь. Например, они могут подумать, что они ввели Foo, но на самом деле они ввели foo, и ваша серверная логика получит foo при отправке формы, это не то, что, по мнению пользователя, они предоставили вам.

Как сделать две отдельные системы? Один для просмотра и изменения имен, а другой для работы с электронной почтой отдельно?

Antarctica-UFO 04.09.2024 11:33

Добавьте к нему прослушиватель событий отдельно, вот так: jsfiddle.net/RoryMcCrossan/217fucLs. Однако, как я уже упоминал выше, вам не нужно этого делать при использовании валидаторов HTML.

Rory McCrossan 04.09.2024 11:35

Здесь не показано, как создать две отдельные системы. Электронная почта ничего не делает. Куда вы вставляете коды для почты?

Antarctica-UFO 04.09.2024 12:20

Я думал, это очевидно — вы поместили это там, где я написал «обработать ввод электронной почты здесь…»

Rory McCrossan 04.09.2024 12:27

это не то же самое. Я попытался добавить что-то, как вы, для имен, но оно туда не помещается, я получаю красные ' и ) в коде Visual Studio (если только там не нужно что-то еще).... можете ли вы что-нибудь добавить там вроде как предотвратить более 1 @ и подряд . чтобы я мог посмотреть, пожалуйста?

Antarctica-UFO 04.09.2024 12:32

Тогда ты сделал это неправильно. Я бы посоветовал задать новый вопрос по этому поводу, если у вас возникли проблемы, хотя, честно говоря, это очень простой синтаксис JS. Возможно, поищите несколько руководств

Rory McCrossan 04.09.2024 12:38

Спасибо за помощь, но повторная публикация того же вопроса без каких-либо изменений не принесет мне никакой пользы. Думаю, я найму кого-нибудь для написания кода.

Antarctica-UFO 04.09.2024 12:59
Ответ принят как подходящий

Во-первых, даже не обязательно нужен обработчик 'DOMContentLoaded' для работы с событиями, связанными с входными элементами 'keypress', если запрос элемента для регистрации последнего начинается после того, как целевой элемент/ы стали доступными в DOM.

Во-вторых, независимо от того, регистрируется ли обработка событий в 'DOMContentLoaded', всегда следует использовать делегирование событий для обработки событий, связанных с входными элементами 'keypress'.

Можно было бы зарегистрировать прослушиватель событий в ближайшем доступном родительском элементе всех задействованных входных элементов. Затем основному обработчику просто нужно проверить и различить соответствующие входные элементы, чтобы перенаправить обработку, специфичную для типа элемента/имени элемента, в связанную, более специализированную функцию-обработчик целевого элемента.

Редактировать

Описанный выше и реализованный ниже подход (делегирование событий) достигает именно того, о чем недавно просил ФП в одном из комментариев...

«Как сделать две отдельные системы? Одна для просмотра и изменения имен, а другая для работы с электронной почтой отдельно?» Антарктида-НЛО // Комментарий: 1 час назад

function handleNameFieldKeypress(target, evt) {
  console.info('handleNameFieldKeypress ... target ...', target);

  const char = String.fromCharCode(evt.which);

  const { selectionStart } = target;

  const isNotValid = (selectionStart === 0 && (

    evt.code === 'Space' ||
    !/^[a-zA-Z]$/.test(char)

  )) || (

    char === ' ' &&
    target.value.charAt(selectionStart - 1) === ' '
  );
  if (isNotValid) {

    evt.preventDefault();
  }
}
function handleEmailFieldKeypress(target, evt) {
  console.info('handleEmailFieldKeypress ... target ...', target);

  const { selectionStart } = target;

  const isNotValid =
    (selectionStart === 0 && evt.code === 'Space') || (

      String.fromCharCode(evt.which) === '@' &&
      target.value.charAt(selectionStart - 1) === '@'
    );

  if (isNotValid) {
    evt.preventDefault();

    return;
  }
  const key = evt.keyCode || evt.charCode || evt.which;

  return (key !== 32) && key;
}

function handleInputFieldKeypress(evt) {
  const { target } = evt;

  let result;

  if (target.matches('input[name = "real_name"], input[name = "display_name"]')) {

    result = handleNameFieldKeypress(target, evt);

  } else if (target.matches('input[name = "email"]')) {

    result = handleEmailFieldKeypress(target, evt);
  }
  return result;
}

document
  .addEventListener('DOMContentLoaded', () => {

    document
      .querySelector('form')
      .addEventListener('keypress', handleInputFieldKeypress);
  });
body { margin: 0; }
form { width: 32%; }
fieldset { margin: 0 0 8px 0; }
label, label > span { display: block; }
label > span { margin: 4px 0 2px 0; }
/*
input[name = "email"],
input[name = "real_name"],
input[name = "display_name"] { text-transform: capitalize; }
*/
.as-console-wrapper { left: auto!important; width: 66%; min-height: 100%; }
<form>
  <fieldset>
    <legend>User Data</legend>
  
    <label>
      <span>Real Name</span>
      <input type = "text" name = "real_name" />
    </label>
  
    <label>
      <span>Display Name</span>
      <input type = "text" name = "display_name" />
    </label>

  </fieldset>
  <fieldset>
  
    <label>
      <span>E-mail Address</span>
      <input type = "email" name = "email" />
    </label>

  </fieldset>
</form>

<!--
<script>

// - one does not even need a 'DOMContentLoaded' event listener
//   for dealing with input-element related 'keypress' events,
//   as long as the element-query starts after the targeted
//   element/s have been made accessible within the DOM.

function handleNameFieldKeypress(target, evt) {
  console.info('handleNameFieldKeypress ... target ...', target);

  const char = String.fromCharCode(evt.which);

  const { selectionStart } = target;

  const isNotValid = (selectionStart === 0 && (

    evt.code === 'Space' ||
    !/^[a-zA-Z]$/.test(char)

  )) || (

    char === ' ' &&
    target.value.charAt(selectionStart - 1) === ' '
  );
  if (isNotValid) {

    evt.preventDefault();
  }
}
function handleEmailFieldKeypress(target, evt) {
  console.info('handleEmailFieldKeypress ... target ...', target);

  const { selectionStart } = target;

  const isNotValid =
    (selectionStart === 0 && evt.code === 'Space') || (

      String.fromCharCode(evt.which) === '@' &&
      target.value.charAt(selectionStart - 1) === '@'
    );

  if (isNotValid) {
    evt.preventDefault();

    return;
  }
  const key = evt.keyCode || evt.charCode || evt.which;

  return (key !== 32) && key;
}

function handleInputFieldKeypress(evt) {
  const { target } = evt;

  let result;

  if (target.matches('input[name = "real_name"], input[name = "display_name"]')) {

    result = handleNameFieldKeypress(target, evt);

  } else if (target.matches('input[name = "email"]')) {

    result = handleEmailFieldKeypress(target, evt);
  }
  return result;
}
document
  .querySelector('form')
  .addEventListener('keypress', handleInputFieldKeypress);

</script>
//-->

@Антарктида-НЛО ... посмотри мой ответ выше. Его подход и реализация достигают именно того, о чем вы спрашивали час назад в одном из своих комментариев... "Как мне сделать две отдельные системы? Одна для просмотра и изменения имен, а другая для работы с электронной почтой отдельно?" Антарктида-НЛО

Peter Seliger 04.09.2024 13:11

Вау, спасибо! Мне нужно всего лишь еще 2 вещи из этого сейчас! Как разрешить только один символ @ во всем электронном письме. И заставить имена начинаться с 1 заглавной буквы, за которой следуют все строчные буквы, специальные символы или цифры в этом слове (второе слово в имени подчиняется тем же правилам, но первая буква пишется с заглавной буквы...). После этого я закончил со всеми своими формами :) Еще раз спасибо Петр Селигер, ты гений!

Antarctica-UFO 04.09.2024 15:15

В дополнение вы задаете еще одну задачу (или две), не связанную с проблемой, которую вы описали в этой теме. Поскольку вы предоставили подход, который обрабатывает то, о чем вы просите, все остальное необходимо описать и свести в пример в другой теме. Я не против предложить решение, когда требования внутри потока меняются или суммируются. Я почти всегда оказываю помощь немедленно. Но я сейчас в отпуске. Никакого кодирования для SO в ближайшие недели.

Peter Seliger 04.09.2024 22:00

Другие вопросы по теме

Щелчок правой кнопкой мыши по кнопке не вызывает событие
Как разработать систему событий и обработчиков событий, используя универсальный код на C#?
Единый обработчик событий в коде C# для всех пользовательских кнопок/MAUI .NET8
Как заполнить текстовое поле с помощью php ajax в каждой строке таблицы при изменении другого текстового поля в строке
Как обновлять модель (данных), связанную с формой, при каждом изменении данных формы?
Проблемы с обнаружением событий после использования контекстного меню в JavaFX (Linux)
Win32 API (C): окно постоянно исчезает во время выполнения после смены фокуса?
Аудиоэлемент HTML5: визуальные элементы кнопки для воспроизведения звука не обновляются при нажатии, а ждут, пока звук не начнет воспроизводиться (проблема с мобильным iOS)
Подкомпонент Vue 3 вызывает событие щелчка при отображении
Как обрабатывать щелчок мыши или наведение курсора мыши на значок ErrorProvider в WinForms