[javascript] Firefox에서 클릭하는 동안 마우스가 움직이면 HTML 레이블이 해당 입력을 트리거하지 않습니다.

다음 예제에서 레이블을 클릭하면 입력 상태가 변경됩니다.

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에서 mousedownmouseup이벤트 간에 커서를 이동하면 입력이 계속 트리거되는 반면 Firefox에서는 확인란이 상태를 변경하지 않습니다.

이 문제를 해결하는 방법이 있습니까? (JavaScript 이벤트 리스너를 사용하지 않고)

Firefox 버전 : 69.0.3 (64-bit)

크롬을 사용할 때의 모든 행동.

  1. 라벨 위의 버튼을 누르십시오
  2. 버튼을 누른 상태에서 커서를 레이블 밖으로 이동하십시오.
  3. 커서를 라벨로 되돌립니다.
  4. 버튼에서 손을 떼십시오


답변

소개

질문에 답변에 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하고 레이블 의 속성을 제거하여 브라우저에 버그가 다시 발생하지 않도록 한 다음 이벤트를 버블 링 한 후 setTimeoutof 0ms를 사용 하여 for속성을 다시 추가하십시오 . 즉, event.preventDefault호출 할 필요가 없으므로 다른 조치 / 이벤트가 취소되지 않습니다. 또한이 기능을 재정의 해야하는 경우 속성 을 호출 Event#preventDefault하거나 제거 하는 이벤트 리스너를 추가하면 for됩니다.

manageLabel

함수manageLabel레이블이 이벤트 리스너에 이미 추가되었는지 확인하여 다시 추가하지 않도록하고, 리스너가 아직 추가되지 않은 경우 추가하고, 관리 된 레이블 목록에 추가합니다.

onLoad

이 함수는 onLoad페이지가 함수가 너무로드되는 경우 전화를받을 필요가 manageLabel그 순간에 DOM에있는 모든 라벨 호출 할 수 있습니다. 이 기능은 또한 MutationObserver 를 사용 하여로드가 시작된 후 (그리고 스크립트가 실행 된 후) 추가되는 레이블을 포착합니다.

위에 표시된 코드는 Martin Barker에 의해 최적화되었습니다 .


답변

JS 이벤트 리스너를 원하지 않았지만 움직임을 식별하는 것이 아니라 클릭 대신 mousedown을 사용하고 있다고 생각한다고 생각합니다 (mousedown 다음에 mouseup).

이것은 Firefox에서 알려진 버그이지만 mousedown 이벤트 를 사용하여 해결할 수 있습니다.

유효한 ID로 ID를 변경해야했습니다 .ID는 문자로 시작해야합니다.

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>


답변

아니요. 이것은 코드 문제가 아닌 파이어 폭스 버그처럼 보입니다. 이 동작에 대한 CSS 해결 방법이 있다고 생각하지 않습니다.

모질라에보고하여 문제를 해결할 수는 있지만 그것에 의존하지는 않습니다. https://bugzilla.mozilla.org/home

잠재적 인 해결 방법을 위해 대신 mouseup에서 이벤트를 트리거하는 것이 좋습니다.


답변

자바 스크립트가 없으면 입력 “id”값과 동일한 “for”값이있는 레이블을 클릭하면 입력이 클릭되지만 브라우저간에 일관성이 없습니다.

브라우저가 위의 사항을 준수하면 자바 스크립트 클릭 이벤트가 효과를 취소하여 아무것도하지 않습니다.

해결책

브라우저간에 일관성을 유지하기 위해 다른 전략을 채택 할 수 있습니다. Onload는 ‘data-for’에 대한 ‘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) .on ( ‘click’, ‘.item’, function (event) {});

과거 에이 주제를 읽었을 때, 요소를 드래그하려는 시도로 행동을 이해하는 것은 Firefox에 달려 있습니다. 그러나 사용자 선택이 없기 때문에 기본 동작을 막습니다.

이것은 상당히 제한된 지식을 기반으로하지만 알려진 버그 / 기발한 것으로 보이며 이것을 지원하는 몇 가지 기사가 있습니다.


답변