使用MutationObserver检测scrollHeight更改?

时间:2017-06-08 06:38:46

标签: mutation-observers

如何使用scrollHeight检测DOM元素何时发生MutationObserver更改?它不是属性,也不是数据。

背景:我需要检测滚动条何时出现在我的内容元素上,其中overflow-y设置为自动。我认为滚动条出现的瞬间scrollHeight的值从0跳到500,所以我的想法就是设置一个MutationObserver来检测这个属性的变化。

到目前为止我得到了什么:

HTML

<div class="body" #body>

CSS

.body {
    overflow-y: auto;
}

打字稿

export class MyWatchedContent implements AfterViewInit, OnDestroy {
   @ViewChild('body', { read: ElementRef })
   private body: ElementRef;

   private observer: MutationObserver;

   public ngAfterViewInit() {
       this.observer = new MutationObserver(this.observerChanges);
       this.observer.observe(this.body.nativeElement, {
           attributes: true,
       });
   }

   public ngOnDestroy() {
       this.observer.disconnect();
   }

   private observerChanges(records: MutationRecord[], observer: MutationObserver) {
       console.log('##### MUTATION');
       records.forEach((_record) => {
           console.log(_record);
       });
   }
}

例如,如果我在开发者窗口中更改背景颜色,我可以看到观察者触发

  突变      

my-content-watcher.component.ts?d0f4:233 MutationRecord {type:“attributes”,target:div.body,addedNodes:NodeList(0),removedNodes:NodeList(0),previousSibling:null ...} < / p>

但是,如果我更改窗口大小以使滚动条显示,则检测不到突变。是否可以使用MutationObserver,如果是这样,怎么做?

2 个答案:

答案 0 :(得分:4)

这是答案,适用于仍在寻找解决方案的任何人:

到目前为止,无法直接监视元素的scrollHeight变化

  • MutationObserver 检测到DOM树中的变化,这可能表明scrollHeight发生了变化,但这是一个疯狂的猜测。
  • ResizeObserver 可检测元素的外部高度的变化,但不能检测scrollHeight(即“内部”高度)的变化。
  • 还没有 ScrollHeight-Observer

但是解决方案非常接近:

解决方案

ResizeObserver检测到元素外部高度的变化...

观察滚动容器没有意义,因为它的外部高度不变。更改其伸出高度的元素是容器的任何CHILD节点!

一旦子节点的高度发生变化,则意味着父容器的scrollHeight发生了变化。

Vanilla JS版本

const container = document.querySelector('.scrollable-container');

const observer = new ResizeObserver(function() {
    console.log('New scrollHeight', container.scrollHeight);
});

// This is the critical part: We observe the size of all children!
for (var i = 0; i < container.children.length; i++) {
    observer.observe(container.children[i]);
})

jQuery版本

const container = $('.scrollable-container');

const observer = new ResizeObserver(function() {
    console.log('New scrollHeight', container[0].scrollHeight);
});

container.children().each(function(index, child) {
    observer.observe(child);
});

进一步的步骤

动态添加子级后,您可以添加MutationObserver,以在添加新子级后将其添加到ResizeObserver。

答案 1 :(得分:1)

您可以通过在contenteditable元素上添加内部包装元素(例如span),然后在内部元素上添加ResizeObserver侦听器来模拟此行为。内部span必须为display:block,否则不会触发ResizeObserver

HTML

<div contenteditable id="input"><span id="content">Some content</span></div>

CSS

#input {
  max-height: 100px;
  overflow: scroll;
  white-space: pre-wrap;
}

#content {
  display: block;
  white-space: pre-wrap;
}

JS

const content = document.getElementById("content");
const observer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    console.warn(entry);
  }
});

observer.observe(content);