Firefox'ta tıklama sırasında fare hareket ettirilirse HTML Etiketi ilgili girişi tetiklemez


13

Aşağıdaki örnekte, etikete tıkladığınızda giriş durumu değişir.

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'da, imleci mousedownve mouseupetkinlikleri arasında hareket ettirdiğinizde giriş yine de tetiklenirken, Firefox'ta onay kutusu durumu değişmez.

Bunu düzeltmenin bir yolu var mı? (JavaScript etkinlik dinleyicilerini kullanmadan)

Firefox sürümü: 69.0.3 (64-bit)

Krom kullanırken tam işlem kümesi.

  1. Etiketin üzerindeki düğmeye basın
  2. Düğmeyi basılı tutarken imleci hareket ettirin (etiketin dışında bile)
  3. İmleci etikete geri döndür
  4. Düğmeyi bırakın

Chrome'da, imleci fareyle üzerine gelme ve fare olayları arasında hareket ettirdiğinizde giriş yine de tetiklenir -> bu benim için krom ve ot olmamalı. bazı fikirler için bir tıklama = fareyle + fareyle .. ilgili: stackoverflow.com/a/51451218/8620333
Temani Afif

@TemaniAfif Chrome'da sizin için durum böyle mi? (ne yaptığımı açıkladığım için). Yoksa hala onay kutusunun durumunu değiştirmiyor mu?
nick zoum

1
Fareyi etiketin üzerinde tutarsak sorun olmaz. hareket bunu etkilememelidir, bu yüzden sanırım bir Firefox
böceğiyle

2
Bu, firfox hata portalında UNCONFIRMED durumu olarak kaydedilen bir hatadır, "Bir" tıklama "etkinliği yalnızca fareyle üzerine gelindiğinde ve fare ile aynı konumdaysa gerçekleşmelidir" bug url'yi kontrol edebilirsiniz: bugzilla.mozilla.org/show_bug. cgi? id = 319347
Jadli

1
Katılıyorum, imleci hareket ettirmek bile 1pxetkileşimi kıracak.
nick zoum

Yanıtlar:


3

Giriş

Soruda özellikle cevabın JavaScript içermemesi gerektiğini belirtmiş olmama rağmen, tüm cevaplar JavaScript ile çalıştı.
Bu bir Firefox hatası gibi göründüğü ve bu noktada gönderilen cevapların çoğu da kodumun geri kalanını değiştirmemi gerektireceğinden, bir kez çalıştırılabilecek bir komut dosyası oluşturmaya karar verdim, ne zaman olursa olsun tüm etiketlerle ilgilenecek dom'a eklenirler ve diğer scriptlerim üzerinde en az etkiye sahip olurlar.

Çözüm - Örnek

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>

açıklama

onLabelClick

onLabelClickBir etiket tıklandığında fonksiyonun çağrılması gerekir, etiketin karşılık gelen bir giriş elemanı olup olmadığını kontrol eder. Eğer varsa, bu kaldırmak için söz konusu tetikleyecek fortarayıcılar kullanmak sonra-tetiği yeniden ve olmayacaktır hata yok ki etiketin niteliğini setTimeoutait 0mseklemek için forolay köpürdü sonra nitelik geri. Bu, event.preventDefaultçağrılmak zorunda olmadığı anlamına gelir ve bu nedenle başka hiçbir işlem / etkinlik iptal edilmez. Ayrıca bu işlevi geçersiz kılmak gerekirse, sadece özniteliği çağıran Event#preventDefaultveya kaldıran bir olay dinleyicisi eklemek zorundayım for.

manageLabel

İşlevmanageLabelbir etiketin yeniden eklenmesini önlemek için önceden bir etkinlik dinleyicisi eklenmiş olup olmadığını kontrol eder, daha önce eklenmemişse dinleyiciyi ekler ve yönetilen etiket listesine ekler.

onLoad

Fonksiyon onLoadsayfa fonksiyonu böylece yüklenen çağrılacak görmesin manageLabelo anda DOM tüm etiketler için çağrılabilir. İşlev ayrıca , yük tetiklendikten (ve komut dosyası çalıştırıldıktan sonra) eklenen etiketleri yakalamak için bir MutationObserver kullanır .

Yukarıda gösterilen kod Martin Barker tarafından optimize edildi .


Kod, gerek duymayan bazı kontroller ve bazı pahalı CPU Çevrimleri yaparak biraz optimize edilmemiş, bunu sizin için optimize ettim pastebin.com/FDXwQL1d
Barkermn01

HTMLLabelElementHem HTMLElement hem de tagName'in bir etiket olup olmadığını kontrol ile değiştirdiği denetimi kaldırmaz
Barkermn01

zeki ama aşırı derecede karmaşık
Steve Tomlin

2

JS Olay dinleyicileri istemediğinizi biliyorum, ama im bu hareket değil tanımlamak istediğinizi düşünüyorum ama tıklama yerine mousedown kullanıyor (fareyle ardından fare).

Bu Firefox'ta bilinen bir hata olsa da fareyle üzerine gelme olayını kullanarak bu sorunu çözebilirsiniz

Kimliğinizi, geçerli bir kimlik olması için değiştirmek zorunda kaldım.

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>


Sorun ben bu komut dosyası kullanarak (kullanarak querySelectorAll) sayfa yükleme çalıştırmak ve daha sonra, dom her etiket eklendiğinde olmasıdır. Bu ayrıca Event#preventDefault, bu hataya sahip olmayan tarayıcılara çift tıklamayı önlemek için etiketlere veya genel olarak dom'a eklenen herhangi bir fare olayı dinleyicisini bozabilir. Son olarak, clicketkinliği kullanmak daha iyi olacaktır, çünkü amaçlanan eylemle aynı etkileşime sahip olacaktır. Bunun dışında şimdiye kadar en iyi cevap bu.
nick zoum

@nickzoum preventDefault()sorununuzu çözmek için kodu güncelledim , bu yüzden tarayıcının değiştirmediyse değiştirip değiştirmediğini kontrol ederek çalışır, 150 ms sonra kullanıcının fark etmemesi için yeterince hızlı ve tarayıcının harekete geçecek kadar yavaş eğer yapması gerekeni yapacaksa. bu daha iyi mi?
Barkermn01

0

Hayır. Bu, kodunuzla ilgili bir sorun değil, bir firefox hatası gibi görünüyor. Bu davranış için bir css geçici çözüm olduğuna inanmıyorum.

Mozilla'ya bildirebilir ve sorunu düzeltebilirsiniz, ancak buna güvenmem. https://bugzilla.mozilla.org/home

Olası bir çözüm için olayı fareyle açmayı öneririm.


0

Javascript olmadan, "for" değeri bir girdi "id" değeriyle aynı olan etikete tıkladığınızda giriş tıklanır, ancak bu tarayıcılar arasında tutarlı değildir.

Bir tarayıcı yukarıdakileri takip ederse, javascript click etkinliğiniz, hiçbir şey yapmadan sonuçlanan efekti iptal eder.

Bir çözüm

Tarayıcılar arasında tutarlılık sağlamak için farklı bir strateji kullanabilirsiniz: Onload, 'data-for' için 'için' tüm özelliklerini dinamik olarak değiştirir, böylece orijinal tarayıcı etkilenir. Ardından, tıklama etkinliğinizi her etikete uygulayabilirsiniz.

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",Ben sadece integeged'im, sen nasıl geliyorsun, değil document.addEventListener("DOMContentLoaded",mi?
Barkermn01

Sadece gördüğüm bir yöntemdi ki bu biraz daha x-tarayıcısıydı. Hangisini tercih ederseniz seçin.
Steve Tomlin

-2

Etkinliği belgeye eklemek ve orada gereken öğeyi hedeflemek bu sorunu sıralamalıdır.

$ (Document) .on ('tıklama', '.item', işlev (olay) {});

Geçmişte bu konuyla ilgili okuma yapmak, Firefox'a eyleminizi öğeyi sürükleme girişimi olarak anlamakla ilgilidir, ancak kullanıcı seçimi hiçbiri olmadığından, varsayılan davranışı önler.

Bu oldukça sınırlı bilgiye dayanmaktadır, ancak bilinen bir hata / tuhaflık gibi görünüyor ve bunu destekleyen etrafında birkaç makale var.


Soruda açıkça söyledim without using JavaScript event listeners.
nick zoum

@nickzoum, bu Firefox'ta bilinen bir hata olduğundan, şansın bittiğini düşünüyorum.
Benjamin James Kippax
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.