ResizeObserver
Базовая поддержка Широко распространена
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с июля 2020 года.
Интерфейс ResizeObserver сообщает об изменениях размеров содержимого или области рамки Element или области, ограничивающей SVGElement.
Примечание: Область содержимого — это область, в которой можно разместить содержимое, то есть область рамки за вычетом отступов и ширины рамки. Область рамки включает в себя содержимое, отступы и рамку. Подробное объяснение см. в разделе Модель области.
Конструктор
ResizeObserver()-
Создаёт и возвращает новый объект
ResizeObserver.
Свойства экземпляра
Нет.
Методы экземпляра
ResizeObserver.disconnect()-
Отменяет наблюдение за всеми наблюдаемыми целевыми
Elementэлементами данного наблюдателя. ResizeObserver.observe()-
Начинает наблюдение за указанным
Element. ResizeObserver.unobserve()-
Завершает наблюдение за указанным
Element.
Примеры
В примере resize-observer-text.html (посмотреть исходный код) мы используем наблюдатель изменений размера для изменения font-size заголовка и абзаца при изменении значения ползунка, что приводит к изменению ширины содержащей <div> области. Это демонстрирует, как можно реагировать на изменения размера элемента, даже если они никак не связаны с отображением.
Мы также предоставили флажок для включения и выключения наблюдателя. Если он выключен, текст не будет изменяться в ответ на изменение ширины <div>.
Следующий код на JavaScript:
const h1Elem = document.querySelector("h1");
const pElem = document.querySelector("p");
const divElem = document.querySelector("body > div");
const slider = document.querySelector('input[type="range"]');
const checkbox = document.querySelector('input[type="checkbox"]');
divElem.style.width = "600px";
slider.addEventListener("input", () => {
divElem.style.width = `${slider.value}px`;
});
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
const contentBoxSize = entry.contentBoxSize[0];
h1Elem.style.fontSize = `${Math.max(
1.5,
contentBoxSize.inlineSize / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(
1,
contentBoxSize.inlineSize / 600,
)}rem`;
} else {
h1Elem.style.fontSize = `${Math.max(
1.5,
entry.contentRect.width / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(1, entry.contentRect.width / 600)}rem`;
}
}
console.log("Size changed");
});
resizeObserver.observe(divElem);
checkbox.addEventListener("change", () => {
if (checkbox.checked) {
resizeObserver.observe(divElem);
} else {
resizeObserver.unobserve(divElem);
}
});
Ошибки наблюдения
Реализации, соответствующие спецификации, вызывают события изменения размера до отрисовки (то есть до отображения кадра пользователю). Если имело место событие изменения размера, стили и макет повторно оцениваются, что, в свою очередь, может вызвать дополнительные события изменения размера. Бесконечные циклы из циклических зависимостей устраняются путём обработки только элементов, расположенных глубже в DOM, во время каждой итерации. События изменения размера, которые не удовлетворяют этому условию, откладываются до следующей отрисовки, и на объекте Window генерируется событие об ошибке с определённой строкой сообщения:
Цикл ResizeObserver завершён с непроданными уведомлениями.
Обратите внимание, что это предотвращает зависание пользовательского агента, но не сам бесконечный цикл. Например, следующий код приведёт к неограниченному увеличению ширины divElem с указанным выше сообщением об ошибке в консоли, повторяющимся в каждом кадре:
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
entry.target.style.width = entry.contentBoxSize[0].inlineSize + 10 + "px";
}
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
До тех пор, пока событие об ошибке не будет генерироваться бесконечно, наблюдатель изменения размера стабилизируется и даёт стабильную, скорее всего правильную, компоновку. Однако пользователи могут увидеть кратковременное нарушение компоновки, так как последовательность изменений, которая должна произойти в одном кадре, вместо этого происходит в нескольких кадрах.
Чтобы предотвратить эти ошибки, решение зависит от того, какой эффект вы хотите получить. Если вы действительно хотите бесконечный цикл, вам нужно отложить код изменения размера в вашем обратном вызове ResizeObserver до момента, когда браузер перерисует содержимое. Вы можете поместить его в обратный вызов requestAnimationFrame.
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
entry.target.style.width = entry.contentBoxSize[0].inlineSize + 10 + "px";
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
Если вы не хотите бесконечного цикла, убедитесь, что ваш код изменения размера не вызывает обратный вызов наблюдателя изменения размера. Есть много способов сделать это, например, задать «ожидаемый размер» и не изменять размер, если размер уже соответствует этому значению.
const divElem = document.querySelector("body > div");
const expectedSizes = new WeakMap();
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
const expectedSize = expectedSizes.get(entry.target);
if (entry.contentBoxSize[0].inlineSize === expectedSize) {
continue;
}
const newSize = entry.contentBoxSize[0].inlineSize + 10;
entry.target.style.width = `${newSize}px`;
expectedSizes.set(entry.target, newSize);
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
Спецификации
Совместимость с браузерами
| Рабочий стол | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
ResizeObserver |
64 | 79 | 69 | 51 | 13.1 | 64 | 79 | 47 | 13.4 | 9.0 | 64 |
ResizeObserver |
64 | 79 | 69 | 51 | 13.1 | 64 | 79 | 47 | 13.4 | 9.0 | 64 |
disconnect |
64 | 79 | 69 | 51 | 13.1 | 64 | 79 | 47 | 13.4 | 9.0 | 64 |
observe |
64 | 79 | 69 | 51 | 13.1 | 64 | 79 | 47 | 13.4 | 9.0 | 64 |
unobserve |
64 | 79 | 69 | 51 | 13.1 | 64 | 79 | 47 | 13.4 | 9.0 | 64 |
См. также
- Урок: Модель области
PerformanceObserver-
IntersectionObserver(часть API наблюдателей пересечения) - Скоро появятся запросы к контейнерам, которые могут стать подходящей альтернативой для реализации адаптивного дизайна.
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver