FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

ResizeObserver是什么? #166

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

新来的产品经理,想做一个和qq或者微信聊天一样的,上下拖动动态改变文本内容框和编辑器布局的需求。 其实一开始是一头雾水的,但是通过万能的mdn,以及充满智慧的我,最终还是完成了这个需求。 其中最核心的还是ResizeObserver这个第一次用的类,所以会在这里做一些记录。

FrankKai commented 4 years ago

ResizeObserver初识

entries是一个数组,它由所有的ResizeObserverEntry object组成。通过for (let entry of entries) {}的方式,entry代表一个ResizeObserver object,一个entry由contentRect和target组成。

在resize相关实践中,entry的contentRect对象是最最重要的。

{target: div, contentRect: DOMRectReadOnly}
contentRect: DOMRectReadOnly
bottom: 312.3125
height: 292.3125
left: 20
right: 626
top: 20
width: 606
x: 20
y: 20
__proto__: DOMRectReadOnly
target: div
__proto__: ResizeObserverEntry
FrankKai commented 4 years ago

ResizeObserver实战

Make element resizable

<div class="main" :style="{minHeight: dynamicMainHeight}">
      <chatView></chatView>
</div>
.main {
    resize: vertical;
    overflow: auto;
}
 observeChatView() {
    if (window.ResizeObserver) {
      const viewElem = document.querySelector('.main');
      const resizeObserver = new ResizeObserver((entries) => {
        for (const entry of entries) {
          if (!this.initialHeight) {
            this.initialHeight = entry.contentRect.height;
          }
          if (this.initialHeight) {
            const deltaHeight = this.initialHeight - entry.contentRect.height;
            this.$bus.$emit('rerenderViewAndEditor', deltaHeight);
          }
        }
      });
      resizeObserver.observe(viewElem);
    } else {
      this.$Message.warning('不支持ResizeObserver');
    }
  },
},

动态计算的editor组件

<div
  class="rich-text-editor"
  contenteditable
  data-placeholder="按下Enter发送消息,按下Shift+Enter换行"
  :style="{height: dynamicHeight}"
></div>
computed: {
  dynamicHeight() {
    return `${defaultEditorHeight + this.deltaHeight}px`;
  },
},
this.$bus.$on('rerenderViewAndEditor', (deltaHeight) => {
    this.deltaHeight = deltaHeight;
});

动态计算的view组件

自动跳到最新一条消息的chatView组件需要减去deltaHeight,从而增大scrollHeight的高度。

this.$bus.$on('rerenderViewAndEditor', (deltaHeight) => {
  this.visiableHeight = document.body.clientHeight - deltaHeight;
  this.deltaHeight = deltaHeight;
});

scrollToBottom() {
  this.$nextTick(() => {
    this.scrollTop = this.scrollHeight - this.deltaHeight;
  });
},

最终效果

FrankKai commented 4 years ago

参考资料

https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver https://github.com/mdn/dom-examples/blob/master/resize-observer/resize-observer-text.html