- 之前初探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();
}
}
-
由于各个浏览器的规则不一样,同样一个加粗操作,没人规定浏览器是应该给文本套个
<b>
标签还是给<span>
加个font-weight:bold;
的 CSS 样式来实现。于是最后在各个浏览器互相编辑的产物,就造成不可控、不可预期。同时还有因为时代的遗留,造成方法本身设计逻辑缺陷的问题。 -
<p class="line"><span>滴滴滴滴</span></p>
这段代码选中第二个滴执行execCommand
方法加粗时,会变为<p class="line">滴滴<b>滴</b>滴</p>
也就是会把外层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阶段(业务需求评审),未来或许大有可为。