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

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

    execCommand 兼容性的分析

    如图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();

    }

    }

    由于各个浏览器的规则不一样,同样一个加粗操作,没人规定浏览器是应该给文本套个 标签还是给 加个 font-weight:bold; 的 CSS 样式来实现。于是最后在各个浏览器互相编辑的产物,就造成不可控、不可预期。同时还有因为时代的遗留,造成方法本身设计逻辑缺陷的问题。

    滴滴滴滴

    这段代码选中第二个滴执行execCommand方法加粗时,会变为

    滴滴

    也就是会把外层span标签给覆盖掉,这样一来使得达到预期的效果的话维护dom成本又变高了。

    execCommand 代替方案

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

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

    2.将输入的内容转换为内部文档模型(在dom层上进行一层抽象,利用js结构对象来描述视图和操作),防止直接操作dom,影响性能。例如quill的Delta用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阶段(业务需求评审),未来或许大有可为。