Cafedev chia sẻ về sự tập trung(focus), làm mờ trong Javascript. Một phần tử nhận được tiêu điểm khi người dùng nhấp vào nó hoặc sử dụng phím Tab trên bàn phím. Ngoài ra còn có một thuộc tính autofocus trong HTML đặt tiêu điểm vào một phần tử theo mặc định khi tải trang và các phương tiện khác để lấy tiêu điểm.

Tập trung vào một phần tử thường có nghĩa là: “chuẩn bị chấp nhận dữ liệu ở đây”, vì vậy đó là thời điểm chúng ta có thể chạy code để khởi tạo chức năng cần thiết.

Khoảnh khắc mất nét (“mờ”) có thể còn quan trọng hơn. Đó là khi người dùng nhấp vào một nơi khác hoặc nhấn Tab để chuyển đến trường biểu mẫu tiếp theo hoặc có các phương tiện khác.

Nói chung, mất tiêu điểm có nghĩa là: “dữ liệu đã được nhập”, vì vậy chúng ta có thể chạy mã để kiểm tra hoặc thậm chí để lưu vào máy chủ, v.v.

Có những đặc thù quan trọng khi làm việc với các sự kiện trọng tâm. Chúng ta sẽ làm những gì tốt nhất để đề cập đến chúng hơn nữa.

1. Sự kiện lấy nét / làm mờ

Sự kiện focus được gọi là khi lấy nét và blur- khi phần tử mất tiêu điểm.

Hãy sử dụng chúng để xác thực một trường đầu vào.

Trong ví dụ dưới đây:

  • Trình xử lý blur kiểm tra xem trường có email được nhập hay không, và nếu không – sẽ hiển thị lỗi.
  • Trình xử lý focus ẩn thông báo lỗi (trên blur đó sẽ được kiểm tra lại):
<style>
  .invalid { border-color: red; }
  #error { color: red }
</style>

Your email please: <input type="email" id="input">

<div id="error"></div>

<script>
input.onblur = function() {
  if (!input.value.includes('@')) { // not email
    input.classList.add('invalid');
    error.innerHTML = 'Please enter a correct email.'
  }
};

input.onfocus = function() {
  if (this.classList.contains('invalid')) {
    // remove the "error" indication, because the user wants to re-enter something
    this.classList.remove('invalid');
    error.innerHTML = "";
  }
};
</script>

Modern HTML cho phép chúng ta làm được nhiều việc phê chuẩn sử dụng thuộc tính đầu vào: required, pattern và vân vân. Và đôi khi chúng chỉ là những gì chúng ta cần. JavaScript có thể được sử dụng khi chúng ta muốn linh hoạt hơn. Ngoài ra, chúng tôi có thể tự động gửi giá trị đã thay đổi đến máy chủ nếu nó chính xác.

2. Phương thức lấy nét / làm mờ

Phương thức elem.focus()và elem.blur() đặt / bỏ đặt sự tập trung vào phần tử.

Ví dụ: hãy làm cho khách truy cập không thể rời khỏi đầu vào nếu giá trị không hợp lệ:

<style>
  .error {
    background: red;
  }
</style>

Your email please: <input type="email" id="input">
<input type="text" style="width:220px" placeholder="make email invalid and try to focus here">

<script>
  input.onblur = function() {
    if (!this.value.includes('@')) { // not email
      // show the error
      this.classList.add("error");
      // ...and put the focus back
      input.focus();
    } else {
      this.classList.remove("error");
    }
  };
</script>

Nó hoạt động trên tất cả các trình duyệt ngoại trừ Firefox .

Nếu chúng ta nhập một cái gì đó vào đầu vào và sau đó cố gắng sử dụng Tab hoặc nhấp vào từ <input>, sau đó onblur trả lại tiêu điểm(focus).

Xin lưu ý rằng chúng ta không thể “ngăn chặn mất focus” bằng cách gọi event.preventDefault() vào onblur, vì nó onblur hoạt động sau khi phần tử bị mất tiêu điểm(focus).

Mất tiêu điểm(focus) do JavaScript khởi tạo

Mất tiêu điểm(focus) có thể xảy ra vì nhiều lý do.

Một trong số đó là khi khách truy cập nhấp vào một nơi khác. Nhưng chính JavaScript cũng có thể gây ra nó, ví dụ:

  • Một alert tiêu điểm di chuyển vào chính nó, vì vậy nó gây ra mất tiêu điểm tại phần tử (  sự kiện blur) và khi alert bị loại bỏ, tiêu điểm sẽ quay trở lại ( sự kiện focus).
  • Nếu một phần tử bị xóa khỏi DOM, thì nó cũng gây ra mất tiêu điểm. Nếu nó được lắp lại sau đó, thì tiêu điểm sẽ không trở lại.

Các tính năng này đôi khi khiến focus/blur trình xử lý hoạt động sai – kích hoạt khi không cần thiết.

Công thức tốt nhất là hãy cẩn thận khi sử dụng các sự kiện này. Nếu chúng ta muốn theo dõi sự mất tiêu điểm do người dùng khởi tạo, thì chúng ta nên tránh tự mình gây ra nó.

3. Cho phép tập trung vào bất kỳ phần tử nào: tabindex

Theo mặc định, nhiều yếu tố không hỗ trợ lấy nét.

Danh sách này khác nhau một chút giữa các trình duyệt, nhưng có một điều luôn đúng: focus/blur hỗ trợ được đảm bảo cho các yếu tố mà một người truy cập có thể tương tác với: <button>, <input>, <select>, <a> và vân vân.

Mặt khác, các phần tử đó tồn tại để định dạng một cái gì đó, chẳng hạn như <div>, <span>, <table> – là unfocusable theo mặc định. Phương thức elem.focus() này không hoạt động trên chúng và các sự kiện focus/blur không bao giờ được kích hoạt.

Điều này có thể được thay đổi bằng cách sử dụng thuộc tính HTML tabindex.

Bất kỳ phần tử nào cũng trở thành tiêu điểm nếu có tabindex. Giá trị của thuộc tính là số thứ tự của phần tử khi Tab(hoặc tương tự như vậy) được sử dụng để chuyển đổi giữa chúng.

Đó là: nếu chúng ta có hai phần tử, phần tử đầu tiên có tabindex=”1″và phần tử thứ hai có tabindex=”2″, sau đó nhấn Tab trong khi ở phần tử đầu tiên – chuyển tiêu điểm vào phần tử thứ hai.

Thứ tự chuyển đổi là: các phần tử có tabindex từ 1 trở lên đi trước (theo thứ tự tabindex), sau đó đến các phần tử không có tabindex(ví dụ: một thông thường <input>).

Các phần tử có khớp tabindex được chuyển theo thứ tự nguồn tài liệu (thứ tự mặc định).

Có hai giá trị đặc biệt:

  • tabindex=”0″ đặt một phần tử trong số những người không có tabindex. Đó là, khi chúng ta chuyển đổi các phần tử, các phần tử tabindex=0 đi sau các phần tử với tabindex ≥ 1.

    Thông thường, nó được sử dụng để làm cho một phần tử có thể lấy tiêu điểm, nhưng hãy giữ thứ tự chuyển đổi mặc định. Để làm cho một phần tử trở thành một phần của biểu mẫu ngang hàng với <input>
  • tabindex=”-1″chỉ cho phép lấy nét theo chương trình vào một phần tử. Các Tab chìa khóa bỏ qua các phần tử như vậy, nhưng phương thức  elem.focus() hoạt động.

Ví dụ, đây là một danh sách. Nhấp vào mục đầu tiên và nhấn Tab:

Click the first item and press Tab. Keep track of the order. Please note that many subsequent Tabs can move the focus out of the iframe in the example.
<ul>
  <li tabindex="1">One</li>
  <li tabindex="0">Zero</li>
  <li tabindex="2">Two</li>
  <li tabindex="-1">Minus one</li>
</ul>

<style>
  li { cursor: pointer; }
  :focus { outline: 1px dashed green; }
</style>

Trình tự là như thế này: 1 – 2 – 0. Thông thường, <li> không hỗ trợ lấy nét, nhưng tabindex đầy đủ cho phép nó, cùng với các sự kiện và tạo kiểu :focus.

Thuộc tính elem.tabIndex cũng hoạt động

Chúng ta có thể thêm tabindex từ JavaScript bằng cách sử dụng thuộc tính elem.tabIndex. Điều đó có tác dụng tương tự.

4. Ủy quyền: focusin / focusout

Sự kiện focus và blur không cơ chế sủi bọt.

Ví dụ, chúng ta không thể đưa onfocus vào <form> để làm nổi bật nó, như thế này:

<!-- on focusing in the form -- add the class -->
<form onfocus="this.className='focused'">
  <input type="text" name="name" value="Name">
  <input type="text" name="surname" value="Surname">
</form>

<style> .focused { outline: 1px solid red; } </style>

Ví dụ trên không hoạt động vì khi người dùng tập trung vào một <input>, sự kiện focus chỉ kích hoạt trên input đó. Nó không có sủi bọt. Vì vậy, form.onfocus không bao giờ kích hoạt.

Có hai giải pháp.

Đầu tiên, có một đặc điểm lịch sử thú vị: focus/blur không nổi bọt, nhưng truyền tải xuống giai đoạn bắt giữ.

Điều này sẽ hoạt động:

<form id="form">
  <input type="text" name="name" value="Name">
  <input type="text" name="surname" value="Surname">
</form>

<style> .focused { outline: 1px solid red; } </style>

<script>
  // put the handler on capturing phase (last argument true)
  form.addEventListener("focus", () => form.classList.add('focused'), true);
  form.addEventListener("blur", () => form.classList.remove('focused'), true);
</script>

Thứ hai, có các sự kiện focusin và focusout – giống hệt như focus/blur, nhưng chúng sủi bọt.

Lưu ý rằng chúng phải được chỉ định bằng cách sử dụng elem.addEventListener, không phải on<event>.

Vì vậy, đây là một biến thể hoạt động khác:

<form id="form">
  <input type="text" name="name" value="Name">
  <input type="text" name="surname" value="Surname">
</form>

<style> .focused { outline: 1px solid red; } </style>

<script>
  form.addEventListener("focusin", () => form.classList.add('focused'));
  form.addEventListener("focusout", () => form.classList.remove('focused'));
</script>

5. Tóm lược

Sự kiện focus và blur kích hoạt trên một phần tử lấy nét / mất tiêu điểm.

Điểm đặc biệt của chúng là:

  • Chúng không cơ chế sủi bọt. Có thể sử dụng trạng thái chụp thay thế hoặc focusin/focusout.
  • Hầu hết các phần tử không hỗ trợ tiêu điểm theo mặc định. Sử dụng tabindex để làm cho bất cứ điều gì có thể làm tiêu điểm(focus).

Phần tử tiêu điểm hiện tại có sẵn dưới dạng document.activeElement.

Nguồn và tài liệu tiếng anh tham khảo:

Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!