富文本编辑器那些事——剪贴板

你对富文本编辑器的那些功能/技术好奇过吗?比如:

  • 编辑器为啥可以输入/插入文本,它是一个 input 或 textarea 吗?

  • 如何知道内容插到哪个位置的?光标是如何定位的?

  • 文本的样式是如何赋予的?

  • 剪贴板是怎么做的?

  • 撤销、重做是怎么回事?

上述的点我都曾经好奇过(不限于),今天作为编辑器第一篇的文章,揭秘一下剪贴板相关知识。

剪贴板概述

在编辑器中复制/剪切的方式有两种:

  • 系统剪贴板:快捷键触发 Ctrl/⌘ + C/X/V
  • 浏览器剪贴板:工具栏或拦截快捷键触发

两种方式的区别:数据储存的位置不同,前者的数据是储存在系统的剪贴板中,后者存在浏览器中。

两者都可以基本满足复制/剪切,但是往往在线编辑器常用浏览器剪贴板,为什么呢?

为什么用浏览器剪贴板?

  1. 触发动作的条件不确定,像最开始说的,用户可能使用快捷键也可能是用编辑器提供的工具栏,当用工具栏时,则需要发一个复制的命令,在客户端肯定是操作浏览器。
  2. 对于复杂元素系统剪贴板不识别,比如复制一个文本绘图插件元素粘贴到编辑器内,复制时需要对该元素进行识别,并且做更多灵活的动作,比如拦截特定情况。
  3. 安全性问题,比较难把控涉及到权限,数据保密等安全问题。

流程

富文本编辑器那些事——剪贴板

事件

事件名称 系统快捷键 主动触发
复制 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 非常方便地操作文本内容,但是它被废弃了,废弃的原因:

  1. 存在安全问题:可以修改浏览器设置、运行脚本 ,容易被恶意攻击。
  2. 浏览器兼容问题:很多特性在不同浏览器操作不一致。 上面的示例中,工具栏的按钮置灰就是浏览器不支持的。

取而代之的是 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 其他作用:

  • 可以存储文件类型
  • 可操作的类型有: nonecopycopyLinkcopyMovelinklinkMovemoveall  or  uninitialized
  • 设置拖动的图像: DataTransfer.setDragImage()

Ps:Wiki 中采用这种方式进行数据存取的。

一个操作 clipboard API 的示例片段:

富文本编辑器那些事——剪贴板

navigator.clipboard.write 和 clipboardData.setData 有何区别?

相同点 不同点
触发方式 触发时机/来源 其他
navigator.clipboard.write 都可以向剪贴板写入数据 异步 任何时机,任何 JS 程序 第一次需要用户主动授权(浏览器弹框询问用户,如果拒绝则中断操作)
event.clipboardData.setData 同步 必须是 ClipboardEvent 来源之一(copy、cut、paste)

完整 Demo

预览: slate-demo.stackblitz.io/

源码: stackblitz.com/edit/slate-…

最后

本人最近计划写一个《揭秘富文本编辑器》系列(又名:编辑器那些事),记录曾经对编辑器好奇的一些知识,如果你也感兴趣,可以关注我,有好奇的点,也可以在下方留言评论告诉我,我会在后续更新。

文中有不正确的观点和内容,还望告知,如果觉得写的不错的话,点个赞吧🌹

参考

原文链接:https://juejin.cn/post/7240636320761495610 作者:阿阿阿阿阿阿杰

(0)
上一篇 2023年6月5日 上午10:42
下一篇 2023年6月5日 上午10:53

相关推荐

发表回复

登录后才能评论