Мышь: отмена выделения, невыделяемые элементы
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/selection-range.
У кликов мыши есть неприятная особенность.
Двойной клик или нажатие с движением курсора как правило инициируют выделение текста.
Если мы хотим обрабатывать эти события сами, то такое выделение – некрасиво и неудобно. В этой главе мы рассмотрим основные способы, как делать элемент невыделяемым.
Для полноты картины, среди них будут и такие, которые применимы не только к событиям мыши.
Способ 1: отмена mousedown/selectstart
Проблема: браузер выделяет текст при движении мышью с зажатой левой кнопкой , а также при двойном клике на элемент. Даже там, где это не нужно.
Если сделать двойной клик на таком элементе, то обработчик сработает. Но побочным эффектом является выделение текста браузером.
Текст
Чтобы избежать выделения, мы должны предотвратить действие браузера по умолчанию для события selectstart в IE и mousedown в других браузерах.
Полный код элемента, который обрабатывает двойной клик без выделения:
Двойной клик сюда выведет "Тест", без выделения
При установке на родителя – все его потомки станут невыделяемыми:
Выделение, всё же, возможно
Отмена действия браузера при mousedown/selectstart отменяет выделение при клике, но не запрещает его полностью.
Если пользователь всё же хочет выделить текстовое содержимое элемента, то он может сделать это.
Достаточно начать выделение (зажать кнопку мыши) не на самом элементе, а рядом с ним. Ведь там отмены не произойдёт, выделение начнётся, и дальше можно передвинуть мышь уже на элемент.
Способ 2: снятие выделения постфактум
Вместо предотвращения выделения, можно его снять в обработчике события, после того, как оно уже произошло.
Для этого мы используем методы работы с выделением, которые описаны в отдельной главе Выделение: Range, TextRange и Selection. Здесь нам понадобится всего лишь одна функция clearSelection , которая будет снимать выделение.
Пример со снятием выделения при двойном клике на элемент списка:
У этого подхода есть две особенности, на которые стоит обратить внимание:
- Выделение всё же производится, но тут же снимается. Это выглядит как мигание и не очень красиво.
- Выделение при помощи передвижения зажатой мыши всё ещё работает, так что посетитель имеет возможность выделить содержимое элемента.
Способ 3: свойство user-select
Существует нестандартное CSS-свойство user-select , которое делает элемент невыделяемым.
Оно когда-то планировалось в стандарте CSS3, потом от него отказались, но поддержка в браузерах уже была сделана и потому осталась.
Это свойство работает (с префиксом) везде, кроме IE9-:
Строка до.. Этот текст нельзя выделить (кроме IE9-) .. Строка после
IE9-: атрибут unselectable=«on»
В IE9- нет user-select , но есть атрибут unselectable.
Он отменяет выделение, но у него есть особенности:
- Во-первых, невыделяемость не наследуется. То есть, невыделяемость родителя не делает невыделяемыми детей.
- Во-вторых, текст, в отличие от user-select , всё равно можно выделить, если начать выделение не на самом элементе, а рядом с ним.
Этот текст невыделяем в IE, кроме дочерних элементов
Левая часть текста в IE не выделяется при двойном клике. Правую часть ( em ) можно выделить, т.к. на ней нет атрибута unselectable .
Этот текст невыделяем в IE, кроме дочерних элементов
Итого
Для отмены выделения есть несколько способов:
- CSS-свойство user-select – везде кроме IE9- (нужен префикс, нестандарт).
- Атрибут unselectable=»on» – работает для любых IE (должен быть у всех потомков)
- Отмена действий на mousedown и selectstart :
elem.onmousedown = elem.onselectstart = function() < return false; >;
Какой же способ выбирать?
Это зависит от задач и вашего удобства, а также конкретного случая. Все описанные способы работают.
Недостаток user-select – в том, что посетитель теряет возможность скопировать текст. А что, если он захочет именно это сделать?
В любом случае эти способы не предназначены для защиты от выделения-и-копирования.
Если уж хочется запретить копирование – можно использовать событие oncopy :
Уважаемый копирователь, почему-то автор хочет заставить вас покопаться в исходном коде этой страницы. Если вы знаете JS или HTML, то скопировать текст не составит для вас проблемы, ну а если нет, то увы.
как запретить клик больше одного раза на каждый input
Есть 3 inputa. При нажатии на каждый должно отобразитьcя в консоль значение value. Но надо сделать чтобы сработало на каждом inpute только по одному разу.
let task2 = document.getElementById('task2') task2.addEventListener('click', something); function something(event)
Отслеживать
саша иванов
задан 2 сен 2021 в 10:59
саша иванов саша иванов
23 4 4 бронзовых знака
Вам необходимо полностью отключить инпуты после клика или оставить их рабочими, но больше не выводить в консоль value?
2 сен 2021 в 11:15
второе. оставить инпуты рабочими. но чтобы в консоль value вывелись только по одному разу.
2 сен 2021 в 11:27
если просто removeEventListener то вывод в консоль сработает вообще только один раз. а надо чтобы по одному разу для каждого инпута
2 сен 2021 в 11:31
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
document.querySelectorAll('#task2 input').forEach( i => i.addEventListener('click', something, ) );
Отслеживать
ответ дан 2 сен 2021 в 11:29
user176262 user176262
это аналогично removeEventListener. тогда вывод в консоль сработает вообще только один раз. а надо чтобы по одному разу для каждого инпута
2 сен 2021 в 11:33
@сашаиванов: вывод в консоль сработает для КАЖДОГО инпута только ОДИН РАЗ. Всё верно же.
2 сен 2021 в 11:48
@UModeL Это я добавил выборку и цикл после комментария.
– user176262
2 сен 2021 в 11:48
@Igor: ситуацию не меняет — лучшим ответ не выбран 🙂
2 сен 2021 в 11:50
спасибо всем за помощь!
2 сен 2021 в 12:30
При нажатии на инпут удаляем обработчик для этого инпута:
let task2 = document.querySelectorAll('#task2 input'); task2.forEach(el => el.addEventListener('click', something)); function something(event)
EDIT
Вариант от Igor более предпочтителен в использовании, т.к. структура кода проще и не нуждается в пояснении
Event.preventDefault()
Метод preventDefault () интерфейса Event сообщает User agent, что если событие не обрабатывается явно, его действие по умолчанию не должно выполняться так, как обычно. Событие продолжает распространяться как обычно, до тех пор, пока один из его обработчиков не вызывает методы stopPropagation () или stopImmediatePropagation () , любой из которых сразу же прекращает распространение.Как отмечено ниже, вызов метода preventDefault () для события, не подлежащего отмене, например события, отправленного через EventTarget.dispatchEvent () , без указания cancelable: true не имеет эффекта.
Синтаксис
event.preventDefault();
Пример
По умолчанию щелчок по флажку переключает его состояние на противоположное. В этом примере показано, как предотвратить такое поведение:
doctype html> html> head> title>Пример preventDefaulttitle> script> function stopDefAction(evt) evt.preventDefault(); > document .getElementById("my-checkbox") .addEventListener("click", stopDefAction, false); script> head> body> p>Пожалуйста, щёлкните по флажку.p> form> input type="checkbox" id="my-checkbox" /> label for="my-checkbox">Checkboxlabel> form> body> html>
Вы можете посмотреть работу preventDefault в действии здесь.
В следующем примере некорректный ввод останавливается и вводимый символ не добавляется в поле с preventDefault() .
DOCTYPE html> html> head> title>Пример preventDefaulttitle> script>
function Init() var myTextbox = document.getElementById("my-textbox"); myTextbox.addEventListener("keypress", checkName, false); > function checkName(evt) var charCode = evt.charCode; if (charCode != 0) if (charCode 97 || charCode > 122) evt.preventDefault(); alert( "Пожалуйста, используйте только буквы нижнего регистра на латинице" + "\n" + "charCode: " + charCode + "\n", ); > > >
script> head> body onload="Init ()"> p>Пожалуйста, введите своё имя, используя только буквы нижнего регистра на латинице.p> form> input type="text" id="my-textbox" /> form> body> html>
Результат выполнения кода:
Примечания
Вызов preventDefault на любой стадии выполнения потока событий отменяет событие, а это означает, что любое действие по умолчанию обычно принимается реализацией, как результат события, которое не произойдёт.
Примечание: В Gecko 6.0, вызов preventDefault() приводит к event.defaultPrevented к переходу значения в состояние True .
Вы можете использовать event.cancelable (en-US) чтобы проверить, является ли событие отменяемым. Вызов preventDefault для неотменяемых событий не имеет никакого эффекта.
preventDefault не останавливает дальнейшее распространение событий на DOM. Для этого следует использовать event.stopPropagation (en-US) .
Спецификации
| Specification |
|---|
| DOM Standard # ref-for-dom-event-preventdefault③ |
Совместимость с браузерами
BCD tables only load in the browser
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 3 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Курсы javascript
Здравствуйте.
При привязке события click к родителю, событие срабатывает и при клике на дочерние элементы. Проблема состоит в том, что у меня дочерние элементы иногда выходят за рамки родителя, к которому привязано событие. Нужно при этом запретить вызов события при клике на тот участок, что выходит за рамки родителя.
Google может много рассказать о том, как запретить вызов события при клике на дочерний элемент. Но мне нужен полный запрет дочернего элемента. Нужен запрет только на том участке дочернего элемента, который выходит за рамки родителя.
Ссылка на песочницу — http://jsfiddle.net/7uw5b/ — с демонстрацией проблемы. В комментариях ещё раз описана задача.
Если перефразировать, то нужно чтобы клик вызывался только при клике на область в пределах границ родителя и никак не реагировал при клике на дочерние элементы, которые полностью «ВНЕ ГРАНИЦ» родителя или на УЧАСТКИ дочерних элементов, которые находятся вне границ родителя.
Подобное вообще возможно?
Буду благодарен любым подсказкам.
PS: В примере иcпользуется jQuery, но против ответов на чистом JS также ничего не имею.
