Thứ năm, 16/04/2020 | 00:00 GMT+7

Xem xét API JavaScript của trình quan sát thay đổi kích thước


Resize Observer là một API JavaScript mới rất giống với các API quan sát khác như API Intersection Observer . Nó cho phép các phần tử được thông báo khi kích thước của chúng thay đổi.

Lý do thường xuyên nhất khiến kích thước phần tử thay đổi là khi khung nhìn được thay đổi kích thước hoặc hướng của thiết bị thay đổi giữa dọc và ngang. Cho đến thời điểm này, ta đã phải dựa vào sự kiện global window.resize để lắng nghe các sự kiện thay đổi kích thước và kiểm tra xem các phần tử nhất định có thay đổi kích thước hay không. Điều này có thể dễ dàng dẫn đến các vấn đề về hiệu suất do lượng lớn sự kiện được kích hoạt. Nói cách khác, sử dụng window.resize thường lãng phí vì nó thông báo cho ta về mọi thay đổi kích thước khung nhìn, không chỉ khi kích thước của phần tử thực sự thay đổi.

Ngoài ra còn có một trường hợp sử dụng khác cho API Resize Observer mà sự kiện thay đổi kích thước của cửa sổ không thể giúp ta : khi các phần tử được thêm vào hoặc xóa khỏi DOM động, ảnh hưởng đến kích thước của phần tử mẹ. Điều này ngày càng xảy ra thường xuyên hơn với các ứng dụng một trang hiện đại.

Cách sử dụng cơ bản

Sử dụng Resize Observer đơn giản như việc khởi tạo một đối tượng ResizeObserver mới và chuyển vào một hàm gọi lại để nhận các mục được quan sát:

const myObserver = new ResizeObserver(entries => {
  // iterate over the entries, do something.
});

Sau đó, ta có thể gọi quan sát trên cá thể của bạn và chuyển vào một phần tử để quan sát:

const someEl = document.querySelector('.some-element');
const someOtherEl = document.querySelector('.some-other-element');

myObserver.observe(someEl);
myObserver.observe(someOtherEl);

Với mỗi mục nhập, ta nhận được một đối tượng có contentRect và thuộc tính đích . Mục tiêu là yếu tố DOM chính nó, và contentRect là một đối tượng với các thuộc tính sau: chiều rộng, chiều cao, x, y, top, right, bottomtrái.

Không giống như getBoundsClientRect của một phần tử, các giá trị của contentRect cho chiều rộng và chiều cao không bao gồm các giá trị đệm. contentRect.top là phần đệm trên cùng của phần tử và contentRect.left là phần đệm bên trái của phần tử.


Ví dụ: nếu ta muốn ghi lại chiều rộng và chiều cao của phần tử được quan sát khi kích thước của phần tử thay đổi, ta có thể làm như sau:

const myObserver = new ResizeObserver(entries => {
  entries.forEach(entry => {
    console.log('width', entry.contentRect.width);
    console.log('height', entry.contentRect.height);
  });
});

const someEl = document.querySelector('.some-element');
myObserver.observe(someEl);

Demo đơn giản

Dưới đây là một minh chứng đơn giản để thấy API Resize Observer đang hoạt động. Hãy thử bằng cách thay đổi kích thước cửa sổ trình duyệt của bạn và lưu ý cách góc gradient và nội dung văn bản chỉ thay đổi khi kích thước của phần tử thực sự bị ảnh hưởng:


Hãy chia nhỏ bản demo đơn giản này. Đầu tiên, ta bắt đầu với một số đánh dấu đơn giản:

<div class="box">
  <h3 class="info"></h3>
</div>
<div class="box small">
  <h3 class="info"></h3>
</div>

Và một loạt các phong cách:

.box {
  text-align: center;
  height: 20vh;
  border-radius: 8px;
  box-shadow: 0 0 4px var(--subtle);

  display: flex;
  justify-content: center;
  align-items: center;
}

.box h3 {
  color: #fff;
  margin: 0;
  font-size: 5vmin;
  text-shadow: 0 0 10px rgba(0,0,0,0.4);
}

.box.small {
  max-width: 550px;
  margin: 1rem auto;
}

Lưu ý ta không cần áp dụng nền gradient cho phần tử .box . Trình quan sát thay đổi kích thước sẽ được gọi một lần khi trang tải lần đầu tiên và sau đó gradient của ta sẽ được áp dụng.

Bây giờ, điều kỳ diệu xảy ra khi ta thêm mã JavaScript sau:

const boxes = document.querySelectorAll('.box');

const myObserver = new ResizeObserver(entries => {
  for (let entry of entries) {
    const infoEl = entry.target.querySelector('.info');
    const width = Math.floor(entry.contentRect.width);
    const height = Math.floor(entry.contentRect.height);

    const angle = Math.floor(width / 360 * 100);
    const gradient = `linear-gradient(${ angle }deg, rgba(0,143,104,1) 50%, rgba(250,224,66,1) 50%)`;

    entry.target.style.background = gradient;

    infoEl.innerText = `I'm ${ width }px and ${ height }px tall`;
  }
});

boxes.forEach(box => {
  myObserver.observe(box);
});

Ở đây ta đang lặp lại các mục trong lệnh gọi lại của người quan sát bằng cách sử dụng vòng lặp for… of , nhưng việc gọi forEach trên các mục nhập sẽ hoạt động giống nhau.

Lưu ý ta cũng phải lặp lại các phần tử mà ta có thể quan sát và gọi observe trên mỗi phần tử.

Hỗ trợ trình duyệt

Hỗ trợ trình duyệt hiện tại khá tệ, chỉ có Chrome 64+ hỗ trợ Resize Observer ra khỏi hộp. Rất may, có một polyfill ta có thể sử dụng trong thời gian cần thiết. Polyfill dựa trên API MutationObserver .

Bạn có thể truy cập Tôi có thể sử dụng server thay đổi kích thước không? để theo dõi hỗ trợ cho tính năng này trên các trình duyệt chính.


Tags:

Các tin liên quan

Thanh tiến trình trang với các biến JavaScript và CSS
2020-04-16
Xem xét API control panel JavaScript
2020-04-16
Xem xét Đề xuất Nhà điều hành Đường ống JavaScript
2020-04-16
Cách triển khai các phương thức mảng JavaScript từ Scratch
2020-04-09
Các đống nhị phân và hàng đợi ưu tiên qua JavaScript
2020-04-05
JavaScript bất biến có thể thay đổi
2020-04-02
Hiểu các tham số mặc định trong JavaScript
2020-03-31
Cookie là gì và cách làm việc với chúng bằng JavaScript
2020-03-19
Tham quan nhanh về date-fns, Thư viện ngày JavaScript đơn giản
2020-03-18
Phương thức getOwnPropertyDescriptors trong JavaScript
2020-03-12