用 `resize` 和 MutationObserver 实现缩放 DOM 并记录尺寸

使用 `resize: vertical` 和 MutationObserver 实现调整任意元素的尺寸,并且记录它的尺寸以备再次使用。

我厂既然号称“机器编程”,DSL 便属于基础配置。于是,各个产品几乎都需要用到 CodeMirror,用于在线写代码。大家的屏幕分辨率不同,对编辑器的大小要求也不同,最简单的办法就是让大家自己调整,并且将尺寸保存在本地。

以前的做法会复杂一些:

  1. 拿一个元素作为 handle 放在角落里
  2. mousedown 时开始侦听 mousemove,动态调整文本框大小
  3. mouseup 时保存尺寸

如今大家应该都有注意到,<textarea> 右下角多了一个缩放用的 handle。这个功能自然不是 <textarea> 独享,而是受 CSS 样式 resize 控制,任何块级元素都适用。MDN 文档在此,建议大家先好好看一遍。

基于一般的网格化设计,包括响应式的需求,编辑器的宽度是固定的,用户控制的只有高度,所以我们只需要设置 resize: vertical,让它接受垂直方面的缩放就可以了。

接下来该侦听缩放事件。可惜,resize 事件只有 window 可以触发(MDN 文档),所以直接在元素上侦听是不可能的了。好在我们有 MutationObserver,而 Resize Observer 也刚刚从草案变成现实,所以曲线一下就能满足这个需求。

onEditorResize([{target}]) {
  const height = target.clientHeight;
  if (height < 160) {
    return;
  }
  localStorage.setItem(EDITOR_HEIGHT, height);
},

mounted() {
  const onResize = debounce(this.onEditorResize, 1000);
  const observer = this.observer = new MutationObserver(onResize);
  observer.observe(element, {
    attributes: true,
  });
},

beforeDestroy() {
  if (this.observer) {
    this.observer.disconnect();
    this.observer = null;
  }
}

这里有几个 tips:

  1. 我用 Vue,所以用到一些生命周期的钩子
  2. 缩放动作会触发多次事件,所以最好用 debounce 降低执行频率
  3. 编辑器需要设置一个最小高度,不然可能不小心存一个 0px ,用户就看不到编辑器了
  4. 关于参数及含义,大家好好看文档吧。

作者: meathill

爱编程,爱旅游,爱吐槽。 今年的目标是完成并运营至少一个 Side Project。 《Electron + Vue 实战开发》龟速创作中……

欢迎吐槽,请勿装死

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据