ResizeObserver-适应性强的新功能强大的工具

朋友们,美好的一天!

响应式是Web开发的标准之一。屏幕分辨率很多,并且这个数字一直在增加。我们努力支持所有可能的屏幕尺寸,同时保持友好的用户界面。媒体查询(媒体查询)是解决此问题的绝佳方法。但是网络组件呢?现代Web开发基于组件,我们需要一种使它们响应的方法。今天,我想谈谈ResizeObserver API,它允许您监视(观察)特定元素(而不是整个视口)的大小变化,而不是像媒体查询那样监视整个视口。

一点历史


以前,我们只有媒体查询可供使用-一种CSS解决方案,基于媒体设备的屏幕大小,类型和分辨率(媒体设备指的是计算机,电话或平板电脑)。媒体查询非常灵活且易于使用。长期以来,媒体查询仅在CSS中可用,现在它们也通过window.matchMedia(mediaQueryString)在JS中可用。现在,我们可以检查从哪个设备查看了该页面,还可以监视查看区域大小的变化(我们正在谈论MediaQueryList.addListener()方法-大约。

元素查询


我们缺少的功能是监视单个DOM元素的大小,而不仅仅是整个视口的大小。多年来,开发人员一直对此抱怨。这是最令人期待的功能之一。在2015年,甚至提出了一个提案-集装箱尺寸要求(集装箱查询):
开发人员在调整其父容器大小时通常需要具有样式元素的能力,而无论其查看区域是什么。集装箱尺寸的要求给了他们这个机会。CSS用法示例:
.element:媒体(最小宽度:30em)屏幕{***}
听起来不错,但浏览器供应商有充分的理由拒绝该建议-循环依赖(循环依赖)(当一种尺寸定义另一种尺寸时,这会导致无限循环(有关更多信息,请参见此处))。还有什么其他选择?我们可以使用window.resize(回调),但这是“昂贵的乐趣”-每当事件发生时都会调用回调,并且我们将需要进行大量计算才能确定组件的大小确实发生了变化。

使用ResizeObserver API调整监视元素的大小


符合Chrome ResizeObserver API
ResizeObserver API是用于跟踪元素大小调整的接口。这是元素的window.resize事件的一种类似形式。

ResizeObserver API是实时草案。它已经在PC的Chrome,Firefox和Safari中实现。移动支持并不那么令人印象深刻-仅支持Android和Chrome浏览器和Chrome浏览器。不幸的是,不存在成熟的多聚体。可用的多聚体包含一些限制(例如,对调整大小的响应较慢或缺少对平滑过渡的支持)。但是,这不应阻止我们测试此API。让我们开始吧!

示例:在调整元素大小时更改文本


想象一下以下情况-元素内的文本应根据元素的大小而变化。ResizeObserver API提供了两个工具-ResizeObserver和ResizeObserverEntry。ResizeObserver用于跟踪项目的大小,而ResizeObserverEntry包含有关已调整大小的项目的信息。
代码很简单:

<h1> size </h1>
<h2> boring text </h2>

const ro = new ResizeObserver(entries => {
    for(let entry of entries){
        const width = entry.contentBoxSize
        ? entry.contentBoxSize.inlineSize
        : entry.contentRect.width

        if(entry.target.tagName === 'H1'){
            entry.target.textContent = width < 1000 'small' : 'big'
        }

        if(entry.target.tagName === 'H2' && width < 500){
            entry.target.textContent = `I won't change anymore`
            ro.unobserve(entry.target) //  ,     500px
        }
    }
})

//       
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

首先,创建一个ResizeObserver对象,并将回调函数作为参数传递给它:

const resizeObserver = new ResizeObserver((entries, observer) => {
    for(let entry of entries){
        // 
    }
})

每次调整ResizeObserverEntries中包含的元素之一的大小时,都会调用该函数。回调函数的第二个参数是观察者本身。我们可以使用它来例如在满足特定条件时停止跟踪。

回调获取ResizeObserverEntry数组。每个条目均包含观察元素(目标)的尺寸。

for(let entry of entries){
    const width = entry.contentBoxSize
    ? entry.contentBoxSize.inlineSize
    : entry.contentRect.width

    if(entry.target.tagName === 'H1'){
        entry.target.textContent = width < 1000 ? 'small' : 'big'
    }
    ...
}

我们具有三个描述元素大小的属性-borderBoxSize,contentBoxSize和contentRect。它们代表元素的盒模型,我们将在后面讨论。现在谈谈支持。大多数浏览器都支持contentRect,但是显然,此属性将被弃用:
contentRect出现在ResizeObserver的初步开发阶段,仅出于当前兼容性的考虑而添加。将来可能会认为它已过时。


因此,我强烈建议将contentRect与bordeBoxSize和contentBoxSize结合使用。ResizeObserverSize包括两个属性:inlineSize和blockSize,它们可以解释为宽度和高度(前提是我们在文本的水平方向上工作-书写模式:水平)。

元素观察


最后要做的是开始跟踪该项目。为此,我们调用ResizeObserver.observe()。此方法将新目标添加到观察项目列表。我们可以一次将一个或几个元素添加到此列表中:

// resizeObserver(target, options)
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

第二个参数是“可选”。迄今为止,唯一可用的选项是box,它定义了块模型。可能的值是content-box(默认),border-box和device-pixel-content-box(仅Chrome)。在一台ResizeObserver中只能定义一个块模型。

要停止监视,请使用ResizeObserver.unobserve(目标)。要停止跟踪所有元素,请使用ResizeObserver.disconnect()。

块模型


内容框是块的内容,不带填充,边框和边距。边框包括填充和边框(无边距)。



设备像素内容框是元素的内容,以物理像素为单位。我没有看到使用此模型的示例,但似乎在使用画布时可能会派上用场。这是在Github上有关此主题有趣讨论。

观察者什么时候能发现变化?


每次调整目标元素的大小时都会调用一个回调。规格说明如下:

  • 从DOM中添加/删除被观察项时,将触发观察。
  • 当被观察元素的显示属性设置为none时,将触发观察。
  • 观察不适用于“未取代”的线元素。
  • 观察不适用于CSS转换。
  • , , .. , 0,0.

根据第一段,我们可以确定更改其子级时父容器中的更改。ResizeObserver API的这种用法的一个很好的例子是在添加新消息时向下滚动聊天窗口。一个例子可以在这里看到

还记得我之前提到的容器大小查询吗?关于他的循环依赖问题?因此,ResizeObserver API具有内置的解决方案,可以防止“调整大小”的无限循环。在这里阅读

感谢您的关注。

有用的链接:MDN CanIUse

规范开发团队的第一篇文章最受欢迎的polyfil



Source: https://habr.com/ru/post/undefined/


All Articles