O rótulo HTML não aciona a respectiva entrada se o mouse for movido ao clicar no Firefox


13

No exemplo a seguir, quando você clica no rótulo, a entrada muda de estado.

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>

No Chrome, quando você move o cursor entre os eventos mousedowne mouseup, a entrada ainda é acionada, enquanto no Firefox a caixa de seleção não muda de estado.

Existe uma maneira de corrigir isso? (sem usar ouvintes de evento JavaScript)

Versão do Firefox: 69.0.3 (64-bit)

Conjunto completo de ações ao usar o chrome.

  1. Pressione o botão sobre a etiqueta
  2. Mova o cursor (mesmo fora do rótulo) enquanto mantém pressionado o botão
  3. Retorne o cursor de volta ao rótulo
  4. Solte o botão

No Chrome, quando você move o cursor entre os eventos de redução do mouse e mouseup, a entrada ainda é acionada -> não é o meu caso no chrome e não deveria ser. um clique = rato do mouse + mouseup .. relacionado para algumas idéias: stackoverflow.com/a/51451218/8620333 #
Temani Afif

@TemaniAfif Agora é o seu caso no Chrome? (desde que eu esclareci o que estou fazendo). Ou ainda não altera o estado da caixa de seleção?
nick Zoum

11
Se mantivermos o mouse sobre o rótulo, tudo bem. o movimento não deve afetar isso, então eu acho que estamos diante de um bug do Firefox
temanitas Afif

2
este é um erro registrado como status NÃO CONFIRMADO no portal de erros do firfox. O evento "clique" deve ocorrer apenas se a ratoeira e a mouse estiver no mesmo local ", você pode verificar o URL desse
Jadli 15/11/19

11
@TemaniAfif Concordo, mover o cursor até 1pxinterromperá a interação.
nick Zoum

Respostas:


3

Introdução

Embora eu tenha declarado especificamente na pergunta que a resposta não deve envolver JavaScript, todas as respostas funcionaram com JavaScript.
Como isso parece ser um bug do Firefox e a maioria das respostas enviadas neste momento exigiria que eu também alterasse o restante do meu código, decidi criar um script que possa ser executado uma vez, que lidará com todos os rótulos, independentemente de quando eles são adicionados ao domínio e terão o menor impacto nos meus outros scripts.

Solução - Exemplo

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>

Explicação

onLabelClick

A função onLabelClickprecisa ser chamada sempre que um rótulo é clicado e verificará se o rótulo possui um elemento de entrada correspondente. Caso isso foraconteça , ele será acionado, remova o atributo do rótulo para que os navegadores não possuam o bug e não o ative novamente. Em seguida, use um setTimeoutdos 0mspara adicionar o foratributo novamente assim que o evento ocorrer. Isso significa event.preventDefaultque não precisa ser chamado e, portanto, nenhuma outra ação / evento será cancelada. Além disso, se eu precisar substituir essa função, basta adicionar um ouvinte de evento que chame Event#preventDefaultou remova o foratributo.

manageLabel

A funçãomanageLabelaceita um rótulo verifica se já foi adicionado um ouvinte de evento para evitar adicioná-lo novamente, adiciona o ouvinte se ainda não tiver sido adicionado e adiciona-o à lista de rótulos que foram gerenciados.

onLoad

A função onLoadprecisa ser chamada quando a página é carregada, para que a função manageLabelpossa ser chamada para todos os rótulos no DOM naquele momento. A função também usa um MutationObserver para capturar todos os rótulos adicionados depois que a carga foi acionada (e o script foi executado).

O código exibido acima foi otimizado por Martin Barker .


Você código é um pouco unoptimised fazer algumas verificações que não precisam e alguns ciclos de CPU caros, eu ter otimizado para você a pastebin.com/FDXwQL1d
Barkermn01

Não remova a seleção substitui-lo com HTMLLabelElementcheque em vez de tanto um HTMLElement e um cheque que o tagName era uma etiqueta
Barkermn01

inteligente, mas excessivamente complicado #
Steve Tomlin

2

Eu sei que você não queria ouvintes do JS Event, mas estou pensando que você pretende identificar o movimento que isso não acontece, mas que está usando a redução de mousedown em vez de clique (mousedown seguido de mouseup).

Embora este seja um bug conhecido no Firefox, você pode contorná-lo usando o evento mousedown

Eu tive que mudar seu ID para ser um ID válido deve começar com um personagem

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>


O problema é que terei que executar esse script (usando querySelectorAll) no carregamento da página e, toda vez que um rótulo for adicionado ao dom. Isso também pode atrapalhar qualquer ouvinte de evento do mouse adicionado aos marcadores ou ao dom em geral, conforme você usa Event#preventDefaultpara evitar um clique duplo em navegadores que não possuem esse bug. Por fim, usar o clickevento seria melhor, pois teria a mesma interação que a ação pretendida. Fora isso, esta é a melhor resposta até agora.
nick Zoum

@nickzoum Atualizei o código para corrigir o seu preventDefault()problema, para que ele funcione, verificando se o navegador o alterou, se não o for, após 150 ms, rápido o suficiente para o usuário não perceber, e lento o suficiente para que o navegador atue intime se vai fazer o que deveria. isto é melhor?
usar o seguinte código

0

Não. Isso parece um bug do Firefox e não um problema com o seu código. Não acredito que haja uma solução alternativa de CSS para esse comportamento.

Você pode denunciá-lo à Mozilla e corrigir o problema, mas eu não confiaria nisso. https://bugzilla.mozilla.org/home

Para uma solução potencial, sugiro acionar o evento durante a ativação.


0

Sem javascript, quando você clica no rótulo com o valor "for" igual ao valor "id" das entradas, a entrada é clicada, mas isso não é consistente entre os navegadores.

Se um navegador seguir o exemplo acima, o evento click em javascript cancelará o efeito, o que acaba sem fazer nada.

Uma solução

Para ter consistência entre os navegadores, você pode adotar uma estratégia diferente: Onload altere dinamicamente todo o atributo 'for' para 'data-for', para anular o efeito do navegador original. Em seguida, você pode aplicar seu evento de clique a cada marcador.

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",Estou apenas integrado como é que você foi com isso e não document.addEventListener("DOMContentLoaded",?
Barkermn01

Foi apenas um método que vi que é um pouco mais x-browser. Escolha qual você preferir.
21319 Steve Stevelin

-2

Anexar o evento ao documento e direcionar o elemento necessário para lá deve classificar esse problema.

$ (Document) .on ('clique', '.item', function (evento) {});

Ao ler este tópico no passado, cabe ao Firefox entender sua ação como uma tentativa de arrastar o elemento, no entanto, como a seleção do usuário não é nenhuma, apenas impede o comportamento padrão.

Isso se baseia em um conhecimento bastante limitado, mas parece ser um bug / peculiaridade conhecido e existem alguns artigos por aí apoiando isso.


Eu disse explicitamente na pergunta without using JavaScript event listeners.
nick Zoum

@nickzoum, já que este é um bug conhecido no Firefox, acho que você está sem sorte.
Benjamin James Kippax
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.