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


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

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

Firefox 버전 : 69.0.3 (64-bit)

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

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

Chrome에서 mousedown 및 mouseup 이벤트 사이에서 커서를 이동하면 입력이 여전히 트리거됩니다 .> 크롬에서는 그렇지 않으며 그렇지 않아야합니다. a click = mousedown + mouseup .. 일부 아이디어와
관련됨

@TemaniAfif 지금 크롬을 사용하고 계십니까? (내가하고있는 것이 무엇인지 명확히 했으므로). 아니면 여전히 확인란의 상태를 변경하지 않습니까?
nick zoum

1
레이블 위에 마우스를두면 괜찮습니다. 나는 우리가 파이어 폭스 버그에 직면하고있다 생각 때문에 이동이 영향을 미치지 않습니다
Temani Afif에게

2
이것은 firfox 버그 포털에서 확인되지 않은 상태로 기록 된 버그입니다. "마우스 다운과 마우스 업이 같은 위치에있는 경우에만"클릭 "이벤트가 발생해야합니다."버그 URL을 확인할 수 있습니다 : bugzilla.mozilla.org/show_bug cgi? id = 319347
Jadli

1
@TemaniAfif 동의합니다. 커서를 움직이면 1px상호 작용이 중단됩니다.
nick zoum

답변:


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

manageLabel

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

onLoad

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

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


코드가 필요하지 않은 검사와 비싼 CPU 사이클을 수행하는 데 약간의 최적화가 이루어지지 않았습니다. pastebin.com/FDXwQL1d
Barkermn01

HTMLLabelElementHTMLElement 대신
tag로

영리하지만 대규모 overcomplicated
스티브 톰린

2

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>


문제는 querySelectorAll페이지로드 시이 스크립트를 사용하여 (을 사용하여 ) 레이블을 돔에 추가 할 때마다 실행해야한다는 것입니다 . 또한 Event#preventDefault이 버그가없는 브라우저를 두 번 클릭하지 않도록하기 위해 일반적으로 레이블 또는 돔에 추가 된 마우스 이벤트 리스너를 망칠 수 있습니다 . 마지막으로, click의도 된 조치와 동일한 상호 작용을 가지므로 이벤트를 사용하는 것이 좋습니다. 그 외에는 지금까지 가장 좋은 대답입니다.
nick zoum

@ nickzoum preventDefault()문제 를 해결하기 위해 코드를 업데이트 했으므로 브라우저가 변경하지 않은 경우 브라우저가 변경되었는지 확인하여 사용자가 인식하지 못할 정도로 150ms 빠른 후 브라우저가 작동 할 정도로 느리게 작동합니다. 예정된 일을 할 예정이라면 그게 더 낫니?
Barkermn01

0

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

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

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


0

자바 스크립트가 없으면 입력 "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.attachEvent("onreadystatechange",난 그냥 당신이 어떻게 그와 함께 오지 않았다 integeged 해요 document.addEventListener("DOMContentLoaded",?
Barkermn01

그것은 조금 더 많은 x-browser 인 방법이었습니다. 원하는 것을 선택하십시오.
Steve Tomlin

-2

이벤트를 문서에 첨부하고 거기에서 필요한 요소를 타겟팅하면이 문제를 정렬해야합니다.

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

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

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


나는 분명히 질문에 말했다 without using JavaScript event listeners.
nick zoum

@nickzoum Firefox에서 알려진 버그이므로 운이 나쁘다고 생각합니다.
Benjamin James Kippax '11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.