【问题标题】:MutationObserver: How to observe mutations in width/height of flex child?MutationObserver:如何观察 flex child 的宽度/高度的变化?
【发布时间】:2019-01-17 12:11:43
【问题描述】:

鉴于以下 DOM 结构...

<div id="outer-container">
  <div class="side-panel"><div width="200px"/></div>
  <div id="content"><!-- some content --></div>
  <div class="side-panel"><div width="100px"/></div>
</div>

使用以下 CSS 规则...

#outer-container {
  display: 'flex';
  align-items: 'stretch';
  width: '100vw';
  height: '100vh';
}

.side-panel {
  flex-shrink: 0;
}

#content {
  display: 'flex';
  flex-direction: 'column';
  align-items: 'stretch';
  flexGrow: 1;
}

如何观察#content 的宽度/高度的变化?

这通常通过观察style 属性中的突变来完成,并在样式发生更改时检查元素的边界(或其他一些变体)。但是,作为一个 flex 容器和子元素,我注意到当我检查元素的宽度/高度时,它们没有被定义。

更改#content 的大小不会从我的 MutationObserver 产生事件(它使用以下配置:{attributes: true, attributeFilter: ['style']}

我的用例是当#content 宽度减小到某个定义的阈值以下时,将侧面板变成抽屉。我正在使用React,但这似乎是原生 html/js 问题。

帮助不胜感激!

PS:我尝试将#content 上的flex-basis 设置为我选择的阈值,但这没有帮助。我想知道是否应该定义 width 而不是 flex-basis.. 但是我不确定这是否会产生不希望的 flex 行为。

【问题讨论】:

  • 那么你想知道flex修改元素大小后#content元素的宽高吗?
  • 是的。我想随时听听宽度/高度的变化 flex 修改元素大小
  • 这对我来说就像一个 XY 问题:您不应该订阅元素计算样式的更改。相反,您应该订阅导致布局更改的事件,进而更改元素的大小。例如,也许你有一个改变其大小的 CSS 过渡/动画:然后你监听 transitionEndanimationEnd 事件。如果 DOM 正在发生变异,则改为检查 MutationObserver。观察style属性不起作用的原因是它适用于内联样式属性,而不是元素的计算样式。
  • 我希望将此行为抽象为一个纯粹的“布局”组件,而不是将其与外部事件耦合。似乎我最好的选择是监听视口大小的变化(这反过来会导致修改#content 的宽度)。顺便说一句,我没有意识到 MutationObservers 只观察到内联样式属性。感谢您的信息。
  • 你需要一个 ResizeObserver 或 IntersectionObserver,而不是 MutationObserver。

标签: html css flexbox mutation-observers


【解决方案1】:

您可以在内部使用 offsetWidth/offsetHeight 属性、getBoundingClientRect() 方法或 getComputedStyle() 方法一个函数说,checkWidth() 然后在事件或函数改变元素的尺寸时调用该函数。

例如,resize 事件将更改元素的尺寸,因此在触发调整大小事件时运行此函数。


检查并运行以下代码片段,然后调整浏览器大小单击按钮以获取我上面描述的实际示例:

/* JavaScript */

function checkWidth(){
  let e = document.getElementById("content");
  let widthA = window.getComputedStyle(e).width;
  let widthB = e.getBoundingClientRect().width;
  let widthC = e.offsetWidth;

  console.log("getComputedStyle: " + widthA);
  console.log("getBoundingClientRect: " + widthB);
  console.log("offsetWidth: " + widthC);
};

window.addEventListener("resize", checkWidth); //checkWidth() added since "resize" alters your element's dimensions

function editContent(){
  let e = document.getElementById("content");
  e.style.width = "300px";
  
  checkWidth(); //checkWidth() added since editContent() alters your element's dimensions
}

document.getElementById("btn").addEventListener("click", editContent);
/* CSS */

#outer-container {
  display: flex;
  align-items: stretch;
  width: 100vw;
  height: 100vh;
}

.side-panel {
  flex-shrink: 0;
}

#content {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex-grow: 1;
}
<!-- HTML -->

<button id="btn">Click Me</button>
<hr/>
<div id="outer-container">
  <div class="side-panel">
    <div style="width: 200px">Left</div>
  </div>
  <div id="content">Middle</div>
  <div class="side-panel">
    <div style="width: 100px">Right</div>
  </div>
</div>

【讨论】:

  • 这一切都假设窗口调整大小事件是导致#content改变大小的唯一事件:)
  • @Terry 这也是真的。但是我可以将函数与事件侦听器分开,并在进行其他更改时调用该函数。让我稍微修改一下答案。
  • 是的,这可以正常工作。我已经处理了其他可能导致#content 改变大小的事件。至于给出一个最佳答案,我应该先重新提出我的问题吗?答案在技术上并不能解决监控弹性项目中计算样式更改的问题
  • @sookie 是的,如果此解决方案不能完全解决您的问题,我认为改写您的问题会是更好的方法。
猜你喜欢
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 2011-04-05
  • 2016-12-03
  • 2013-10-03
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多