Я хочу захватить событие щелчка по родительскому элементу, когда дочерний элемент отключен (кнопка, ввод или другие элементы могут быть отключены), например этот код
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
приведет к тому, что кнопка не будет получена этой функцией
@Мехди Пока что кажется, что ты прав
Кнопка является дочерней для 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
И event.stopPropagation()
или event.stopImmediatePropagation()
бесполезны
Да, я не указываю параметр :( ошибка. Я попробую по-другому
Случай необычный, так что давайте развлечемся xd
Почему вы используете {capture: false}
? По умолчанию он уже имеет значение false
MDN docs: параметры захвата addEventListener. Кроме того, в вашем конкретном коде <span>
должен (CSS, т. е.:) быть единственной целевой областью, если вы нажмете кнопку по ее краям, код не будет работать. Поэтому ваш абзац "Some keywords:"
вводит в заблуждение.
Спасибо, что указали на это. Я наспех написал ответ из желания быть полезным спрашивающему. Извинения. Я пересмотрел свой ответ. @RokoC.Buljan
Мы могли бы назначить кнопке наложение и удалить его при включении.
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)
Кажется, мое предложение близко к этому stackoverflow.com/questions/20294867/…
@Roko C. Buljan elementsFromPoint может обнаружить отключенную кнопку (вы можете попробовать это с помощью события mousemove, которое можно захватить, когда кнопка отключена)
@肉蛋充肌 Да, я проверил и понял это, а также добавил ответ, который даже включает его, поскольку он действительно помогает обнаружить настоящую кнопку!.
Кажется, на данный момент нет лучшего способа сделать это.
Возможно, вы захотите определить свой собственный способ 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>
Это последний выбор, потому что моя кнопка (и другие базовые компоненты) взяты из сторонней библиотеки компонентов. Но спасибо за дельный совет
<span>
, внутри кнопки disabled
.button
, используя appearance: none; padding: 0;
, чтобы дочерняя область 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(), поэтому добавление дополнительного события в один диапазон у меня не работает.
@肉蛋充肌 Я пропустил ту часть, где вы упоминаете INPUT, TEXTAREA и т. д. Извините, тогда ответ «Нет». Невозможно. Со временем я могу попробовать другие идеи, но боюсь, что проиграю битву с атрибутом [disabled]
.
Лучше всего следовать принятому ответу на этот ответ SO от chiliNUT