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

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

document.querySelector('div').addEventListener('click', () => {
  alert('clicked!')
  // both two ways to stop propagation are useless
  event.stopImmediatePropagation()
  event.stopPropagation()
}, { capture: true })
<div>
  <button disabled>button</button>
</div>

Когда я нажимаю эту кнопку, событие не будет зафиксировано div (стандартно), но я хочу, чтобы это div зафиксировало это событие. Как я могу это сделать?

pointer-events:none у меня не работает, потому что мне нужно использовать document.elementsFromPoint(), чтобы получить эту кнопку и что-то сделать. И pointer-events:noneприведет к тому, что кнопка не будет получена этой функцией

Лучше всего следовать принятому ответу на этот ответ SO от chiliNUT

Mehdi 17.08.2024 17:53

@Мехди Пока что кажется, что ты прав

肉蛋充肌 18.08.2024 11:56
Поведение ключевого слова "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) для оценки ваших знаний,...
1
2
88
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Если кнопка отключена, запустите событие щелчка в div, не передавая событие кнопке при нажатии div.

Если нет, запустите событие кнопки.

Я рекомендую вам попробовать больше вещей самостоятельно.

let span = document.querySelector('span');
let button = document.querySelector('button');
let div = document.querySelector('div');

if (button.disabled) {
  div.addEventListener('click', () => {
    alert('div clicked!');
  });
}

span.addEventListener('mousedown', (e) => {
  div.click();
});

button.addEventListener('click', (e) => {
  alert('button');
})
.myButton {
  margin: 0;
  padding: 0;
  width: 80px;
  height: 32px;
}

.mySpan {
  display: block;
  width: 100%;
  height: 100%;
  line-height: 30px;
}
<div class = "myDiv">
  <button class = "myButton" disabled>
    <span class = "mySpan">button</span>
  </button>
</div>

Сказали, что не могу пользоваться pointer-events: none

肉蛋充肌 17.08.2024 16:45

И event.stopPropagation() или event.stopImmediatePropagation() бесполезны

肉蛋充肌 17.08.2024 17:41

Да, я не указываю параметр :( ошибка. Я попробую по-другому

NINE 17.08.2024 17:44

Случай необычный, так что давайте развлечемся xd

NINE 17.08.2024 18:13

Почему вы используете {capture: false}? По умолчанию он уже имеет значение falseMDN docs: параметры захвата addEventListener. Кроме того, в вашем конкретном коде <span> должен (CSS, т. е.:) быть единственной целевой областью, если вы нажмете кнопку по ее краям, код не будет работать. Поэтому ваш абзац "Some keywords:" вводит в заблуждение.

Roko C. Buljan 17.08.2024 21:45

Спасибо, что указали на это. Я наспех написал ответ из желания быть полезным спрашивающему. Извинения. Я пересмотрел свой ответ. @RokoC.Buljan

NINE 18.08.2024 05:07
Ответ принят как подходящий

Мы могли бы назначить кнопке наложение и удалить его при включении.

document.getElementById('overlay').addEventListener('click', () => {
  // Handle the event as if the disabled button was clicked
  console.info('Overlay clicked, handling as if the disabled button was clicked.');
});
#overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  cursor: not-allowed;
}

/* Hide overlay when button is not disabled */
#myButton:not(:disabled)~#overlay {
  display: none;
}
<div id = "parentDiv" style = "position: relative;">
  <button id = "myButton" disabled>Disabled Button</button>
  <!-- Transparent overlay -->
  <div id = "overlay"></div>
</div>

Прочтите внимательно вопрос: ОП упомянул что-то о elementsFromPoint(). Использование наложения DIV бросает вызов этой вещи. (PS, подумав об этом еще раз, может ли elementsFromPoint() вообще обнаружить кнопку disabled?... в таком случае Q OP будет проблемой XY-PR)

Roko C. Buljan 17.08.2024 22:38

Кажется, мое предложение близко к этому stackoverflow.com/questions/20294867/…

mplungjan 17.08.2024 22:44

@Roko C. Buljan elementsFromPoint может обнаружить отключенную кнопку (вы можете попробовать это с помощью события mousemove, которое можно захватить, когда кнопка отключена)

肉蛋充肌 18.08.2024 10:57

@肉蛋充肌 Да, я проверил и понял это, а также добавил ответ, который даже включает его, поскольку он действительно помогает обнаружить настоящую кнопку!.

Roko C. Buljan 18.08.2024 11:21

Кажется, на данный момент нет лучшего способа сделать это.

肉蛋充肌 18.08.2024 11:58

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

Это означает, что вы отключите кнопку, добавив к кнопке класс disabled, а не используя атрибут disabled.

for(var div of document.querySelectorAll('div')) {
 div.addEventListener('click', () => {
  console.info('The parent was clicked.');
 }, true);
}

for(var button of document.querySelectorAll('button')) {
 button.addEventListener('click', function() {
  if (this.classList.contains('disabled')) {
   console.info('The disabled button was clicked.');
  } else {
   console.info('The button was clicked.');
  }
 });
}
button {
 appearance: none;
 position: relative;
 border: 1px solid black;
 border-radius: 2px;
 background: #E8E8E8;
 color: #CCC;
 &:not(.disabled, [disabled]) {
  color: black;
  cursor: pointer;
  &:hover {
   background: #E0E0E0;
  }
  &:active {
   background: #F0F0F0;
  }
 }
}
<div>
 <button>Enabled Button</button>
 <button class='disabled'>My Button</button>
 <button disabled>Disabled Button></button>
</div>

Это последний выбор, потому что моя кнопка (и другие базовые компоненты) взяты из сторонней библиотеки компонентов. Но спасибо за дельный совет

肉蛋充肌 18.08.2024 10:51
  • Важно: создайте дочерний элемент, например <span>, внутри кнопки disabled.
  • Важно: удалите все стили по умолчанию из button, используя appearance: none; padding: 0;, чтобы дочерняя область SPAN могла полностью захватывать указатель.
  • Назначьте прослушиватель кликов этому селектору SPAN: "button[disabled] > span", который в свою очередь будет эмулировать .click() в родительском DIV.
  • Чтобы дополнительно определить фактический button, используйте elementsFromPoint(x, y) и найдите в возвращаемом массиве элемент BUTTON.

Пример:

const div = document.querySelector("div");
div.addEventListener("click", (evt) => {
  console.info("DIV CLICKED!"); // Works thanks to child SPAN emulating a DIV click
  // You can stop here. DIV finally registers the click.

  // If you want to further detect if a button was clicked
  // and get that actual button Element, use:
  const {clientX:x, clientY:y} = evt;
  const btn = document.elementsFromPoint(x, y).find(el => el.tagName === "BUTTON");
  if (btn) {
    console.info(btn);
  }
});

const spans = div.querySelectorAll("button[disabled] > span");
spans.forEach(btnSpan => {
  // Necessary since the DISABLED button prevents from propagating the Event
  btnSpan.addEventListener("click", (evt) => {
    div.click();
  });
});
* { margin: 0; box-sizing: border-box; }

button {
  appearance: none;
  padding: 0;
}

button span {
  display: block;
  padding: 0.5em 1em;
}
<div>
  <button disabled><span>Disabled with SPAN</span></button>
  <br>
  <button><span>Not Disabled with SPAN</span></button>
</div>

Если вы не можете редактировать HTML напрямую (по какой-то причине), чтобы вставить SPAN внутри ваших BUTTON, вы всегда можете использовать JavaScript:

document.querySelectorAll("button").forEach((btn) => {
  const text = btn.firstChild; // {#text}
  const span = Object.assign(document.createElement("span"), {
    textContent: text.nodeValue
  });
  text.replaceWith(span);
});
button {
  appearance: none;
  padding: 0;
}
button > span {
  display: block;
  padding: 0.5em 1em;
  color: red;
}
<p>Example dynamically inserting SPAN into BUTTONs</p>
<button disabled>Button 1</button>
<button>Button 2</button>

Это жизнеспособный вариант, но в моем сценарии он не работает. 1. Для кнопок это осуществимо! Однако, если это отключенный вход, сделать это кажется невозможным. 2. В моем сценарии мне нужно добавить событие щелчка в самый внешний элемент div и получить соответствующий элемент через elementsFromPoint(), поэтому добавление дополнительного события в один диапазон у меня не работает.

肉蛋充肌 18.08.2024 12:03

@肉蛋充肌 Я пропустил ту часть, где вы упоминаете INPUT, TEXTAREA и т. д. Извините, тогда ответ «Нет». Невозможно. Со временем я могу попробовать другие идеи, но боюсь, что проиграю битву с атрибутом [disabled].

Roko C. Buljan 18.08.2024 12:11

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