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>

क्रोम में, जब आप कर्सर को घटनाओं mousedownऔर mouseupघटनाओं के बीच स्थानांतरित करते हैं तब भी इनपुट ट्रिगर हो जाता है, जबकि फ़ायरफ़ॉक्स में चेकबॉक्स राज्य को नहीं बदलता है।

क्या इसे ठीक करने का कोई तरीका है? (जावास्क्रिप्ट ईवेंट श्रोताओं का उपयोग किए बिना)

फ़ायरफ़ॉक्स संस्करण: 69.0.3 (64-bit)

क्रोम का उपयोग करते समय कार्यों का पूरा सेट।

  1. लेबल पर बटन दबाएं
  2. बटन को दबाए रखते हुए कर्सर को (लेबल के बाहर भी) घुमाएँ
  3. कर्सर को लेबल पर वापस लौटाएं
  4. बटन जारी करें

Chrome में, जब आप मूसडाउन और माउसअप ईवेंट के बीच कर्सर ले जाते हैं, तब भी इनपुट ट्रिगर हो जाता है -> क्रोम और ओट में मेरे लिए ऐसा नहीं होना चाहिए। a click = mousedown + mouseup .. कुछ विचारों से संबंधित: stackoverflow.com/a/51451218/8620333
तैमनी Afif

@TemaniAfif क्या अब क्रोम पर आपके लिए यह मामला है? (जब से मैंने स्पष्ट किया है कि यह मैं क्या कर रहा हूँ)। या क्या यह अभी भी चेकबॉक्स की स्थिति को नहीं बदलता है?
निक जुम

1
यदि हम माउस को लेबल पर रखते हैं तो यह ठीक है। इस कदम से यह प्रभावित नहीं होना चाहिए, इसलिए मुझे लगता है कि हम
टेमानी अफ़ीफ़

2
यह एक बग है, जिसे फ़रफ़ेंग बग पोर्टल में UNCONFIRMED स्टेटस के रूप में लॉग किया गया है, "ए" क्लिक "ईवेंट केवल तभी होना चाहिए जब मूसडाउन और माउसअप एक ही स्थान पर थे" आप वहां बग यूआरएल की जांच कर सकते हैं: बग्लाइला.मोजिला.org/show_bug । cgi? id = 319347
जदली

1
@TemaniAfif मैं सहमत हूं, कर्सर को हिलाने से भी 1pxबातचीत टूट जाएगी।
निक ज़उम

जवाबों:


3

परिचय

हालाँकि मैंने विशेष रूप से इस सवाल में कहा था कि उत्तर में जावास्क्रिप्ट शामिल नहीं होना चाहिए, सभी उत्तरों में जावास्क्रिप्ट के साथ काम किया गया था।
चूंकि यह फ़ायरफ़ॉक्स बग प्रतीत होता है और इस बिंदु पर प्रस्तुत अधिकांश उत्तरों से मुझे अपने बाकी कोड में भी बदलाव करने की आवश्यकता होगी, मैंने एक स्क्रिप्ट बनाने का फैसला किया है जिसे एक बार चलाया जा सकता है, जब चाहे तब सभी लेबल से निपटेंगे। उन्हें डोम में जोड़ा जाता है और मेरी अन्य लिपियों पर सबसे कम प्रभाव पड़ेगा।

समाधान - उदाहरण

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लिए a का उपयोग करें for। इसका मतलब event.preventDefaultहै कि कॉल नहीं करना है और इस प्रकार कोई अन्य कार्य / ईवेंट रद्द नहीं होंगे। इसके अलावा, अगर मुझे इस फ़ंक्शन को ओवरराइड करने की आवश्यकता है, तो मुझे एक घटना-श्रोता को जोड़ना होगा जो कॉल करता है Event#preventDefaultया forविशेषता को निकालता है ।

manageLabel

कार्यक्रमmanageLabelएक लेबल जाँच स्वीकार करता है अगर इसे जोड़ने से बचने के लिए पहले से ही एक इवेंट श्रोता जोड़ा गया है, तो श्रोता को जोड़ता है अगर यह पहले से नहीं जोड़ा गया है, और इसे लेबल की सूची में जोड़ दिया गया है। जब पृष्ठ लोड हो जाता है तो

onLoad

फ़ंक्शन onLoadको कॉल करने की आवश्यकता होती है ताकि manageLabelउस क्षण डोम पर सभी लेबल के लिए फ़ंक्शन को कॉल किया जा सके। लोड को निकाल दिए जाने के बाद फ़ंक्शन किसी भी लेबल को जोड़ने के लिए एक MutationObserver का उपयोग करता है , (और स्क्रिप्ट चला गया है)।

ऊपर प्रदर्शित कोड मार्टिन बार्कर द्वारा अनुकूलित किया गया था ।


आप कुछ अटकलें कर रहे हैं कि कुछ चेक करने की आवश्यकता नहीं है और कुछ महंगा सीपीयू साइकिल है, मैंने इसे आपके लिए pastebin.com/FDXwQL1d
Barkermn01

यह उस चेक को नहीं हटाता है जो इसे HTMLLabelElementHTMLElement और चेक के बजाय चेक के साथ बदल देता है, टैगनाम एक लेबल था
बर्कर्मन 01

चतुर लेकिन बड़े पैमाने पर अधित्याग
स्टीव टोमलिन

2

मुझे पता है कि आप जेएस इवेंट श्रोताओं को नहीं चाहते थे, लेकिन यह सोचकर कि आप आंदोलन को पहचानने का मतलब यह नहीं करते हैं, लेकिन क्लिक के बजाय मूसडाउन का उपयोग कर रहे हैं (माउसअप द्वारा पीछा किया गया)।

जबकि यह फ़ायरफ़ॉक्स में एक ज्ञात बग है जिसे आप मूसडाउन इवेंट का उपयोग करके प्राप्त कर सकते हैं

मुझे आपकी आईडी को एक वैध एक आईडी के रूप में बदलना होगा जो कि एक चरित्र से शुरू होनी चाहिए

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ईवेंट का उपयोग करना बेहतर होगा, क्योंकि इसमें इच्छित कार्रवाई के समान इंटरैक्शन होगा। इसके अलावा, यह अब तक का सबसे अच्छा जवाब है।
निकोउ

@nickzoum i ने आपकी preventDefault()समस्या को ठीक करने के लिए कोड को अपडेट किया है, इसलिए यह जाँच कर काम करता है कि क्या ब्राउज़र ने इसे नहीं बदला है या नहीं, 150 ms के बाद उपयोगकर्ता द्वारा इसे नोटिस न करने के लिए काफी तेजी से, और इतना धीमा कि ब्राउज़र ने काम किया होगा अगर यह ऐसा करने जा रहा है तो इसे करने का इरादा है। क्या वो बेहतर है?
बर्कर्मन 01

0

नहीं, यह एक फ़ायरफ़ॉक्स बग की तरह दिखता है और आपके कोड के साथ कोई समस्या नहीं है। मेरा मानना ​​है कि इस व्यवहार के लिए एक सीएसएस समाधान नहीं है।

आप इसे मोज़िला को रिपोर्ट करने और समस्या को हल करने में सक्षम हो सकते हैं, लेकिन मैं उस पर भरोसा नहीं करूंगा। https://bugzilla.mozilla.org/home

संभावित वर्कअराउंड के लिए मैंने इसके बजाय माउसअप पर इवेंट को ट्रिगर करने का सुझाव दिया।


0

जावास्क्रिप्ट के बिना, जब आप उस लेबल पर क्लिक करते हैं, जिसका "" मान "इनपुट के समान" आईडी "मान के समान होता है, तो इनपुट क्लिक हो जाता है, लेकिन यह ब्राउज़रों के बीच संगत नहीं है।

यदि कोई ब्राउज़र उपरोक्त का पालन करता है, तो आपकी जावास्क्रिप्ट क्लिक घटना प्रभाव को रद्द कर देगी, जो कुछ भी नहीं करने पर समाप्त होती है।

एक तरकीब

ब्राउज़रों में एक अलग रणनीति अपना सकते हैं: Onload गतिशील रूप से '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",?
बरकर्मन 01

यह सिर्फ एक विधि थी जिसे मैंने देखा था जो थोड़ा अधिक एक्स-ब्राउज़र है। जो आप कभी भी पसंद करते हैं उसे चुनें।
स्टीव टोमलिन

-2

घटना को दस्तावेज़ में संलग्न करना और उस तत्व को लक्षित करना जहां आपको इस मुद्दे को हल करने की आवश्यकता होगी।

$ (दस्तावेज़) .on ('क्लिक', '.item', फ़ंक्शन (घटना) {});

अतीत में इस विषय पर पढ़ने से, यह फ़ायरफ़ॉक्स को नीचे ले जाता है, जो आपकी कार्रवाई को तत्व को खींचने के प्रयास के रूप में समझता है, क्योंकि उपयोगकर्ता का चयन कोई नहीं करता है, यह सिर्फ डिफ़ॉल्ट व्यवहार को रोकता है।

यह काफी सीमित ज्ञान पर आधारित है लेकिन यह एक ज्ञात बग / विचित्रता है और इसके समर्थन में कुछ लेख तैर रहे हैं।


मैंने स्पष्ट रूप से प्रश्न में कहा without using JavaScript event listeners
निक ज़उम

@nickzoum चूंकि यह फ़ायरफ़ॉक्स में एक ज्ञात बग है, मुझे लगता है कि आप भाग्य से बाहर हैं।
बेंजामिन जेम्स किप्पैक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.