HTML Label не запускает соответствующий ввод, если мышь перемещается при нажатии в Firefox

13

В следующем примере, когда вы нажимаете на метку, вход меняет состояние.

document.querySelector("label").addEventListener("click", function() {
  console.log("clicked label");
});
label {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<input type="checkbox" id="1">
<label for="1">Label</label>

В Chrome, при перемещении курсора между mousedownи mouseupсобытиями вход еще сработал, в то время как в Firefox флажок не изменяет состояние.

Есть ли способ это исправить? (без использования слушателей событий JavaScript)

Версия Firefox: 69.0.3 (64-bit)

Полный набор действий при использовании Chrome.

  1. Нажмите кнопку над ярлыком
  2. Переместите курсор вокруг (даже вне метки), удерживая при этом кнопку
  3. Вернуть курсор обратно на метку
  4. Отпустите кнопку
Ник Зум
источник
В Chrome, когда вы перемещаете курсор между событиями mousedown и mouseup, ввод по-прежнему срабатывает -> для меня это не так в chrome, и не должно быть. клик = MouseDown + MouseUp .. связаны некоторые идеи: stackoverflow.com/a/51451218/8620333
Феманитян Afif
@TemaniAfif Это правда для вас сейчас на Chrome? (так как я уточнил, что я делаю). Или это все еще не меняет состояние флажка?
Ник Зум
1
Если мы будем держать курсор мыши над этикеткой, тогда все в порядке. этот шаг не должен повлиять на это , так что я предполагаю , что мы столкнулись с ошибкой Firefox
Феманитяне Afif
2
это ошибка, которая регистрируется как статус UNCONFIRMED на портале ошибок firfox, событие «щелчка» должно происходить только в том случае, если mousedown и mouseup находились в одном месте «вы можете проверить там URL ошибки: bugzilla.mozilla.org/show_bug. cgi? id = 319347
Jadli
1
@ TemaniAf, если я согласен, перемещение курсора даже 1pxнарушит взаимодействие.
Ник Зум

Ответы:

3

Введение

Хотя я специально указал в вопросе, что ответ не должен включать JavaScript, все ответы работали с JavaScript.
Поскольку это, похоже, ошибка Firefox, и большинство ответов, представленных на этом этапе, потребуют от меня и остальной части моего кода, я решил создать сценарий, который можно запустить один раз, который будет обрабатывать все метки независимо от того, когда они добавляются в домен и будут оказывать наименьшее влияние на другие мои сценарии.

Решение - Пример

var mutationConfiguration = {
  attributes: true,
  childList: true
};

if (document.readyState === "complete") onLoad();
else addEventListener("load", onLoad);

var managingDoms = [];

function onLoad() {
  document.querySelectorAll("label[for]").forEach(manageLabel);
  if (typeof MutationObserver === "function") {
    var observer = new MutationObserver(function(list) {
      list.forEach(function(item) {
        ({
          "attributes": function() {
            if (!(item.target instanceof HTMLLabelElement)) return;
            if (item.attributeName === "for") manageLabel(item.target);
          },
          "childList": function() {
            item.addedNodes.forEach(function(newNode) {
              if (!(newNode instanceof HTMLLabelElement)) return;
              if (newNode.hasAttribute("for")) manageLabel(newNode);
            });
          }
        }[item.type])();
      });
    });
    observer.observe(document.body, mutationConfiguration);
  }
}

function manageLabel(label) {
  if (managingDoms.includes(label)) return;
  label.addEventListener("click", onLabelClick);
  managingDoms.push(label);
}

function onLabelClick(event) {
  if (event.defaultPrevented) return;
  var id = this.getAttribute("for");
  var target = document.getElementById(id);
  if (target !== null) {
    this.removeAttribute("for");
    var self = this;
    target.click();
    target.focus();
    setTimeout(function() {
      self.setAttribute("for", id);
    }, 0);
  }
}
label {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  padding: 10px;
  border: 1px solid black;
  cursor: pointer;
}
<input type="checkbox" id="a">
<input type="text" id="b">
<label for="a">A</label>
<script>
  setTimeout(function() {
    var label = document.createElement("label");
    label.setAttribute("for", "b");
    label.textContent = "b";
    document.body.appendChild(label);
  }, 3E3);
</script>

объяснение

onLabelClick

Функция onLabelClickдолжна вызываться при каждом нажатии метки, она проверит, имеет ли метка соответствующий элемент ввода. Если это произойдет, это вызовет его, удалить forатрибут этикетки , так что браузеры не ошибка не будет повторно вызвать его , а затем использовать setTimeoutиз 0msдля добавления forатрибута обратно после того , как событие пузырилось. Это означает, event.preventDefaultчто не нужно вызывать и, следовательно, никакие другие действия / события не будут отменены. Также, если мне нужно переопределить эту функцию, мне просто нужно добавить прослушиватель событий, который вызывает Event#preventDefaultили удаляет forатрибут.

manageLabel

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

onLoad

Функция onLoadдолжна вызываться при загрузке страницы, чтобы в этот момент ее manageLabelможно было вызывать для всех меток в DOM. Функция также использует MutationObserver для перехвата любых добавляемых меток после того, как загрузка была запущена (и скрипт был запущен).

Код, представленный выше, был оптимизирован Мартином Баркером .

Ник Зум
источник
Ваш код немного неоптимизирован, делает некоторые проверки, в которых он не нужен, и некоторые дорогостоящие циклы ЦП, я оптимизировал его для вас по адресу pastebin.com/FDXwQL1d
Barkermn01
Он не удаляет проверку, он заменяет ее HTMLLabelElementпроверкой вместо HTMLElement и проверки того, что tagName было меткой
Barkermn01
умный, но
Стив Томлин
2

Я знаю, что вам не нужны слушатели событий JS, но я думаю, что вы хотите определить движение, которое это не делает, но использует mousedown вместо click (mousedown, а затем mouseup).

Хотя это известная ошибка в Firefox, вы можете обойти ее, используя событие mousedown

Я должен был изменить ваш идентификатор, чтобы быть действительным один идентификатор должен начинаться с символа

document.querySelector("label").addEventListener("mousedown", function(evt) {
  console.log("clicked label");
  // if you want to to check the checkbox when it happens,
  let elmId = evt.target.getAttribute("for")
  let oldState = document.querySelector("#"+elmId).checked;
  setTimeout(() => {
    if(oldState == document.querySelector("#"+elmId).checked){
      document.querySelector("#"+elmId).checked = !oldState;
    }
  }, 150)
});
label {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<input type="checkbox" id="valid_1">
<label for="valid_1">Label</label>

Barkermn01
источник
Проблема в том, что мне придется запускать этот скрипт (используя querySelectorAll) при загрузке страницы, а затем, каждый раз, когда метка добавляется в DOM. Это также может испортить любые прослушиватели событий мыши, добавленные к ярлыкам или к домену в целом, так как вы используете, Event#preventDefaultчтобы избежать двойного щелчка по браузерам, у которых нет этой ошибки. Наконец, clickлучше использовать событие, так как оно будет иметь то же взаимодействие, что и предполагаемое действие. Кроме этого, это лучший ответ на данный момент.
Ник Зоум
@nickzoum Я обновил код, чтобы исправить вашу preventDefault()проблему, поэтому он работает, проверяя, изменил ли браузер его, если не изменил, через 150 мс достаточно быстро, чтобы пользователь не заметил его, и достаточно медленно, чтобы браузер действовал вовремя, если он собирается делать то, что должен. это лучше?
Barkermn01
0

Нет. Это похоже на ошибку Firefox, а не на проблему с вашим кодом. Я не верю, что есть обходной путь CSS для этого поведения.

Вы можете сообщить об этом в Mozilla и решить проблему, но я бы не стал полагаться на это. https://bugzilla.mozilla.org/home

Для возможного обходного пути я бы предложил вместо этого инициировать событие при mouseup.

Гарет Вебстер
источник
0

Без javascript, когда вы щелкаете по метке, у которой значение «for» совпадает со значением «id» входных данных, происходит щелчок по входу, но это не согласуется в браузерах.

Если браузер следует приведенному выше, событие кликования JavaScript отключит эффект, который в итоге ничего не сделает.

Решение

Чтобы обеспечить согласованность между браузерами, вы можете принять другую стратегию: Onload динамически изменяет все атрибуты «for» на «data-for», так что это обнуляет исходный эффект браузера. Затем вы можете применить событие клика к каждому ярлыку.

var replaceLabelFor = function () {
    var $labels = document.querySelectorAll('label');
    var arrLabels = Array.prototype.slice.call($labels);
    arrLabels.forEach(function (item) {
      var att = document.createAttribute('data-for');
      att.value = String(this.for);
      item.setAttributeNode(att);
      item.removeAttribute('for')
    });
}

var applyMyLabelClick() {
  document.querySelector("label").addEventListener("click", function() {
    console.log("clicked label");
  });
}

// x-browser handle onload
document.attachEvent("onreadystatechange", function(){
  if(document.readyState === "complete"){
    document.detachEvent("onreadystatechange", arguments.callee);
    replaceLabelFor();
    applyMyLabelClick();
  }
});
Стив Томлин
источник
document.attachEvent("onreadystatechange",Я просто размышлял, как получилось, что ты пошел с этим, а нет document.addEventListener("DOMContentLoaded",?
Barkermn01
Это был просто метод, который я видел, который немного больше для X-браузера. Выберите то, что вы предпочитаете.
Стив Томлин
-2

Прикрепление события к документу и нацеливание на элемент, который вам требуется, должно решить эту проблему.

$ (Document) .on ('click', '.item', function (event) {});

Из чтения этой темы в прошлом, Firefox понимает ваши действия как попытку перетаскивания элемента, так как пользователь выбирает значение none, он просто предотвращает поведение по умолчанию.

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

Бенджамин Джеймс Киппакс
источник
Я прямо сказал в вопросе without using JavaScript event listeners.
Ник Зум
@nickzoum, поскольку это известная ошибка в Firefox, я думаю, тебе не повезло.
Бенджамин Джеймс