Nhãn HTML không kích hoạt đầu vào tương ứng nếu chuột bị di chuyển trong khi nhấp vào Firefox


13

Trong ví dụ sau, khi bạn nhấp vào nhãn, trạng thái đầu vào thay đổi.

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>

Trong Chrome, khi bạn di chuyển con trỏ giữa mousedownmouseupcác sự kiện, đầu vào vẫn được kích hoạt, trong khi trong Firefox, hộp kiểm không thay đổi trạng thái.

Có cách nào để sửa lỗi này? (không sử dụng trình nghe sự kiện JavaScript)

Phiên bản Firefox: 69.0.3 (64-bit)

Tập hợp đầy đủ các hành động khi sử dụng chrome.

  1. Nhấn nút trên nhãn
  2. Di chuyển con trỏ xung quanh (ngay cả bên ngoài nhãn) trong khi vẫn giữ nút
  3. Đưa con trỏ trở lại nhãn
  4. Nhả nút

Trong Chrome, khi bạn di chuyển con trỏ giữa các sự kiện mousedown và mouseup, đầu vào vẫn được kích hoạt -> đó không phải là trường hợp của tôi trên chrome và không nên. a click = mousedown + mouseup .. liên quan đến một số ý tưởng: stackoverflow.com/a/51451218/8620333
Temani Afif

@TemaniAfif Bây giờ có phải là trường hợp dành cho bạn trên chrome không? (vì tôi đã làm rõ những gì tôi đang làm). Hoặc nó vẫn không thay đổi trạng thái của hộp kiểm?
nick zoum

1
Nếu chúng tôi giữ chuột trên nhãn thì không sao. Việc di chuyển không ảnh hưởng đến điều này nên tôi đoán chúng ta đang đối mặt với một lỗi của Firefox
Temani Afif

2
đây là một lỗi được ghi là trạng thái UNCONFIRMED trong cổng thông tin lỗi Firfox, sự kiện "nhấp chuột" chỉ xảy ra nếu mousedown và mouseup ở cùng một vị trí "bạn có thể kiểm tra url url: bugzilla.mozilla.org/show_orms. cgi? id = 319347
Jadli

1
@TemaniAfif Tôi đồng ý, di chuyển con trỏ thậm chí 1pxsẽ phá vỡ sự tương tác.
nick zoum

Câu trả lời:


3

Giới thiệu

Mặc dù tôi đặc biệt tuyên bố trong câu hỏi rằng câu trả lời không liên quan đến JavaScript, nhưng tất cả các câu trả lời đều hoạt động với JavaScript.
Vì đây có vẻ là lỗi của Firefox và hầu hết các câu trả lời được gửi vào thời điểm này sẽ yêu cầu tôi thay đổi phần còn lại của mã, tôi đã quyết định tạo một tập lệnh có thể chạy một lần, sẽ xử lý tất cả các nhãn bất kể khi nào chúng được thêm vào dom và sẽ có tác động ít nhất đến các tập lệnh khác của tôi.

Giải pháp - Ví dụ

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>

Giải trình

onLabelClick

Hàm onLabelClickcần được gọi bất cứ khi nào nhãn được nhấp, nó sẽ kiểm tra xem nhãn có thành phần đầu vào tương ứng hay không. Nếu có, nó sẽ kích hoạt nó, loại bỏ các forthuộc tính của nhãn để các trình duyệt không có lỗi sẽ không kích hoạt lại nó và sau đó sử dụng một setTimeoutsố 0msđể thêm forlại thuộc tính một lần sự kiện sôi nổi. Điều này có nghĩa là event.preventDefaultkhông phải gọi và do đó, không có hành động / sự kiện nào khác sẽ bị hủy. Ngoài ra nếu tôi cần ghi đè chức năng này, tôi chỉ cần thêm một trình lắng nghe sự kiện gọi Event#preventDefaulthoặc xóa forthuộc tính.

manageLabel

Chức năngmanageLabelchấp nhận kiểm tra nhãn nếu nó đã được thêm một trình lắng nghe sự kiện để tránh thêm lại nó, thêm trình nghe nếu nó chưa được thêm và thêm nó vào danh sách các nhãn đã được quản lý.

onLoad

Hàm onLoadcần được gọi khi trang được tải để manageLabelcó thể gọi hàm cho tất cả các nhãn trên DOM tại thời điểm đó. Hàm này cũng sử dụng M mutObserver để bắt bất kỳ nhãn nào được thêm vào, sau khi tải được kích hoạt (và tập lệnh đã được chạy).

Mã hiển thị ở trên đã được Martin Barker tối ưu hóa .


Mã của bạn là một chút không được đánh giá cao khi thực hiện một số kiểm tra mà nó không cần và một số chu kỳ CPU tốn kém, tôi đã tối ưu hóa nó cho bạn tại pastebin.com/FDXwQL1d
Barkermn01 22/11/19

Nó không xóa séc mà nó thay thế bằng HTMLLabelElementséc thay vì cả HTMLEuity và séc rằng tagName là nhãn
Barkermn01 22/11/19

thông minh nhưng ồ ạt quá mức
Steve Tomlin

2

Tôi biết bạn không muốn người nghe Sự kiện JS, nhưng tôi nghĩ bạn có nghĩa là xác định chuyển động này không nhưng đang sử dụng mousedown thay vì nhấp chuột (mousedown theo sau là mouseup).

Mặc dù đây là một lỗi đã biết trong Firefox, bạn có thể khắc phục bằng cách sử dụng sự kiện mousedown

Tôi đã phải thay đổi id của bạn thành một id hợp lệ phải bắt đầu bằng một ký tự

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>


Vấn đề là tôi sẽ phải chạy tập lệnh này (sử dụng querySelectorAll) khi tải trang và sau đó, mỗi khi một nhãn được thêm vào dom. Điều này cũng có thể gây rối cho bất kỳ trình lắng nghe sự kiện chuột nào được thêm vào nhãn hoặc dom nói chung khi bạn sử dụng Event#preventDefaultđể tránh nhấp đúp vào các trình duyệt không có lỗi này. Cuối cùng, sử dụng clicksự kiện sẽ tốt hơn, vì nó sẽ có tương tác tương tự như hành động dự định. Ngoài ra, đây là câu trả lời tốt nhất cho đến nay.
nick zoum

@nickzoum tôi đã cập nhật mã để khắc phục sự cố của bạn preventDefault(), vì vậy nó hoạt động bằng cách kiểm tra xem trình duyệt có thay đổi hay không, sau 150 ms đủ nhanh để người dùng không nhận thấy và đủ chậm để trình duyệt có hành động intime nếu nó sẽ làm những gì nó phải làm. tốt hơn không
Barkermn01

0

Không. Điều này trông giống như một lỗi firefox và không phải là vấn đề với mã của bạn. Tôi không tin có một cách giải quyết css cho hành vi này.

Bạn có thể báo cáo vấn đề này với Mozilla và khắc phục sự cố, nhưng tôi sẽ không dựa vào đó. https://ormszilla.mozilla.org/home

Đối với một cách giải quyết tiềm năng, tôi sẽ đề nghị kích hoạt sự kiện trên mouseup thay thế.


0

Không có javascript, khi bạn nhấp vào nhãn có giá trị "for" giống như giá trị "id" đầu vào thì đầu vào sẽ được nhấp, nhưng điều này không nhất quán giữa các trình duyệt.

Nếu một trình duyệt thực hiện theo như trên, thì sự kiện nhấp vào javascript của bạn sẽ hủy hiệu ứng, kết quả là không làm gì cả.

Một giải pháp

Để có sự thống nhất giữa các trình duyệt, bạn có thể áp dụng một chiến lược khác: Onload tự động thay đổi tất cả các thuộc tính 'for' for 'data-for', do đó nó vô hiệu hóa trình duyệt ban đầu. Sau đó, bạn có thể áp dụng sự kiện nhấp chuột của bạn cho mỗi nhãn.

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",Tôi chỉ tích hợp làm thế nào bạn đi với điều đó và không document.addEventListener("DOMContentLoaded",?
Barkermn01

Đó chỉ là một phương pháp mà tôi thấy đó là trình duyệt x nhiều hơn một chút. Chọn cái nào bạn thích.
Steve Tomlin

-2

Đính kèm sự kiện vào tài liệu và nhắm mục tiêu yếu tố bạn yêu cầu trong đó phải sắp xếp vấn đề này.

$ (Tài liệu) .on ('nhấp', '.item', hàm (sự kiện) {});

Từ việc đọc về chủ đề này trong quá khứ, Firefox hiểu hành động của bạn là một nỗ lực kéo phần tử, tuy nhiên, do người dùng chọn là không có, nó chỉ ngăn hành vi mặc định.

Điều này dựa trên kiến ​​thức khá hạn chế nhưng nó dường như là một lỗi / quirk đã biết và có một vài bài viết nổi xung quanh việc hỗ trợ này.


Tôi nói rõ ràng trong câu hỏi without using JavaScript event listeners.
nick zoum

@nickzoum vì đây là một lỗi đã biết trong Firefox, tôi nghĩ bạn đã hết may mắn.
Benjamin James Kippax
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.