剪贴板概述
在编辑器中复制/剪切的方式有两种:
- 系统剪贴板:快捷键触发
Ctrl/⌘ + C/X/V
- 浏览器剪贴板:工具栏或拦截快捷键触发
两种方式的区别:数据储存的位置不同,前者的数据是储存在系统的剪贴板中,后者存在浏览器中。
两者都可以基本满足复制/剪切,但是往往在线编辑器常用浏览器剪贴板,为什么呢?
为什么用浏览器剪贴板?
- 触发动作的条件不确定,像最开始说的,用户可能使用快捷键也可能是用编辑器提供的工具栏,当用工具栏时,则需要发一个复制的命令,在客户端肯定是操作浏览器。
- 对于复杂元素系统剪贴板不识别,比如复制一个文本绘图插件元素粘贴到编辑器内,复制时需要对该元素进行识别,并且做更多灵活的动作,比如拦截特定情况。
- 安全性问题,比较难把控涉及到权限,数据保密等安全问题。
流程
事件
事件名称 | 系统快捷键 | 主动触发 | |
---|---|---|---|
复制 | oncopy | Ctrl/⌘ + C |
document.execCommand('copy') |
剪切 | oncut | Ctrl/⌘ + X |
document.execCommand('cut') |
粘贴 | onpaste | Ctrl/⌘ + V |
document.execCommand('paste') |
示例:
实现方式一:强大的 document.execCommand
这个 API 的木器主要用来操纵编辑器元素的,正如我给的标题,它非常“强大”,强大之处在于它支持的场景/命令非常全,除了上面复制/粘贴/剪切,还有一些以下命令:
命令名称 | 描述 |
---|---|
backColor | 容器元素添加背景颜色 |
bold | 切换文字粗体效果 |
createLink | 创建锚链接 |
fontName | 修改字体 |
fontSize | 修改字体大小 |
heading | 设置标题 |
insertImage | 插入图片 |
insertOrderedList | 插入有序列表 |
justifyLeft/Right/Center | 所选内容文本对齐:左对齐、右对齐、居中对齐 |
outdent | 缩进 |
undo/redo | 撤销/重做 |
underline | 切换下划线 |
示例点 这里 。
Wiki 插件工具栏的复制:
已被废弃
这个 API 非常方便地操作文本内容,但是它被废弃了,废弃的原因:
- 存在安全问题:可以修改浏览器设置、运行脚本 ,容易被恶意攻击。
- 浏览器兼容问题:很多特性在不同浏览器操作不一致。 上面的示例中,工具栏的按钮置灰就是浏览器不支持的。
取而代之的是 Clipboard API,见下节。
实现方式二:Clipboard API
该 API 一般用于剪贴板(复制/剪切/粘贴),相较于 execCommand 可以避免安全问题,同时也更加可靠和跨浏览器兼容。
提供的 API 也都是异步的,返回结构都是 Promise,方法如下:
navigator.clipboard.writeText()
:将文本内容写入剪贴板。navigator.clipboard.readText()
:从剪贴板中读取文本内容。navigator.clipboard.write()
:将数据写入剪贴板。navigator.clipboard.read()
:从剪贴板中读取数据。
clipboardData 和 DataTransfer
clipboardData 绑定于 Clipboard Event(copy、cut、paste),是其属性,数据结构 DataTransfer 对象的一种。
主要作用:
- 访问全局剪贴板数据:
event.clipboardData.setData(format, data)
- 设置全局剪贴板数据:
event.clipboardData.getData(format)
- 清除全局剪贴板数据:
event.clipboardData.clearData()
DataTransfer 其他作用:
- 可以存储文件类型
- 可操作的类型有:
none
,copy
,copyLink
,copyMove
,link
,linkMove
,move
,all
oruninitialized
。 - 设置拖动的图像:
DataTransfer.setDragImage()
Ps:Wiki 中采用这种方式进行数据存取的。
一个操作 clipboard API 的示例片段:
navigator.clipboard.write 和 clipboardData.setData 有何区别?
相同点 | 不同点 | |||
---|---|---|---|---|
触发方式 | 触发时机/来源 | 其他 | ||
navigator.clipboard.write | 都可以向剪贴板写入数据 | 异步 | 任何时机,任何 JS 程序 | 第一次需要用户主动授权(浏览器弹框询问用户,如果拒绝则中断操作) |
event.clipboardData.setData | 同步 | 必须是 ClipboardEvent 来源之一(copy、cut、paste) | 无 |
完整 Demo
预览: https://slate-demo.stackblitz.io/
源码: https://stackblitz.com/edit/slate-demo?file=src%2Fclipboard.component.ts
最后
本人最近计划写一个《揭秘富文本编辑器》系列(又名:编辑器那些事),记录曾经对编辑器好奇的一些知识,如果你也感兴趣,可以关注我,有好奇的点,也可以在下方留言评论告诉我,我会在后续更新。
文中有不正确的观点和内容,还望告知,感谢 🌹