execCommand的问题以及替代方案思考

7,904 阅读2分钟
  • 之前初探execCommand方法,就发现会有很多奇奇怪怪的问题,虽然看似都能解决,但每个问题的成本都会大大增加,该方法不是可控的,在这过程操作dom就必不可免,项目庞大起来可能会感觉不是在开发而是在补坑,且会产生拆东墙补西墙结果。

execCommand 兼容性的分析

截屏2021-04-19 下午6.52.13.png

截屏2021-04-19 下午6.52.26.png

如图caniuse的显示的兼容性表格很好,虽然document.execCommand()方法似乎在现代浏览器都基本支持。但是如insertBrOnReturn一些参数指令还是会大面积的在各种浏览器不支持,无效果。

  • 之前在ios设备下执行document.execCommand('copy')一直返回false且ios下input不支持input.select();无法获取选中文字,如下在ios设备上并无效果,使得想一键复制保存到粘贴板着个功能实现起来不太友好,
const input = document.querySelector('#copy-input');
    if (input) {
      input.value = text;
      if (document.execCommand('copy')) {
        input.select();
        document.execCommand('copy');
        input.blur();
      }
}
  • 由于各个浏览器的规则不一样,同样一个加粗操作,没人规定浏览器是应该给文本套个 <b> 标签还是给 <span> 加个 font-weight:bold; 的 CSS 样式来实现。于是最后在各个浏览器互相编辑的产物,就造成不可控、不可预期。同时还有因为时代的遗留,造成方法本身设计逻辑缺陷的问题。

  • <p class="line"><span>滴滴滴滴</span></p>这段代码选中第二个滴执行execCommand方法加粗时,会变为<p class="line">滴滴<b>滴</b>滴</p>也就是会把外层span标签给覆盖掉,这样一来使得达到预期的效果的话维护dom成本又变高了。

execCommand 代替方案

大多数编辑器都是HTMLcontenteditableexecCommandAPI的包装。所以打算不使用execCommandAPI实现,设计如下:

1.借助HTMLcontenteditable,好处是配合已有的浏览器光标、选区方面的支持。

2.将输入的内容转换为内部文档模型(在dom层上进行一层抽象,利用js结构对象来描述视图和操作),防止直接操作dom,影响性能。例如quillDelta用Json格式描述三种动作和一种属性:

  • insert:插入
  • retain:保留
  • delete:删除 比如要向编辑器中插入Hello,之后将其Hell改为红色并删除最后一个字母o 就可以用Delta进行描述,结果为
{
  "ops": [
    { "insert": "Hello " },
    { "retain": 5 ,"attributes": { "color": "#ff0000" } },
    { "delete": 1 }
  ]
}

这样的数据结构描述操作方式显得非常直观。

3.拦截拖拽,单击,键盘事件。获得selectionState,鼠标位置、和拖拽文字的状态信息。

4.最后改变contentState,利用immutable引入防止引用值被修改,可以让我们更容易的去处理缓存、回退、数据变化检测等问题,简化开发.

另外有个w3c新标准input-events-2,应该是execCommand的修订版和改进版,目前在TR1阶段(业务需求评审),未来或许大有可为。