记录React之富文本编辑器

主要知识点:contentEditable 以及 document.execCommand

日常使用的输入框,大多直接使用input,支持正常的文本操作,但是想要做复杂的内容输入,就需要一个富文本编辑器,所以我就查找资料,开始了一段富文本编辑器的探索之旅。

首先使用的是DOM元素的contentEditable属性,该属性可以将DOM元素改为可编辑状态,也就是点击后可以出现光标,每次点击回车键,都会重新添加一个div节点。利用div可包万物的特性,所以可以通过它来开发一款富文本编辑器。

重点来了,div输入也只能输入正常的文本,如果想加粗,斜体,插入图片,超链接,该怎么办?这就需要用到document.execCommand了,但是这是一个被官方弃用(不再推荐使用)的特性。

当一个 HTML 文档切换到设计模式时,document 暴露 execCommand方法,该方法允许运行命令来操纵可编辑内容区域的元素。

大多数命令影响document的 selection(粗体,斜体等),当其他命令插入新元素(添加链接)或影响整行(缩进)。当使用contentEditable时,调用 execCommand() 将影响当前活动的可编辑元素。

/**
* 语法:
* @param{string} aCommandName 命令的名称
* @param{boolean} aShowDefaultUI 是否展示用户界面
* @param{} aValueArgument 一些命令(例如 insertImage)需要额外的参数(insertImage 需要提供插入 image 的 url),默认为 null。
*/
var bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument);
// 如果执行成功,则返回true,反之,返回false

execCommand可使用的commandName有以下几种:

命令 含义 示例
backColor 修改文档的背景颜色。在 styleWithCss 模式下,则只影响容器元素的背景颜色。这需要一个<color> 类型的字符串值作为参数传入。注意,IE 浏览器用这个设置文字的背景颜色。 document.execCommand(“backColor”, false, “#FF0000”)
bold 开启或关闭选中文字或插入点的粗体字效果。IE 浏览器使用 <strong>标签,而不是<b>标签。
copy 拷贝当前选中内容到剪贴板。启用这个功能的条件因浏览器不同而不同,而且不同时期,其启用条件也不尽相同。使用之前请检查浏览器兼容表,以确定是否可用。
createLink 为选中内容创建超链接,需要一个hrefURI 字符串作为参数值传入。URI 必须包含至少一个字符,例如一个空格。 document.execCommand(“createLink”, false, “https://baidu.com”)
cut 剪贴当前选中的文字并复制到剪贴板。启用这个功能的条件因浏览器不同而不同,而且不同时期,其启用条件也不尽相同。使用之前请检查浏览器兼容表,以确定是否可用。
fontName 在插入点或者选中文字部分修改字体名称。需要提供一个字体名称字符串 (例如:“Arial”) 作为参数。
fontSize 在插入点或者选中文字部分修改字体大小。需要提供一个 HTML 字体尺寸 (1-7) 作为参数。
foreColor 在插入点或者选中文字部分修改字体颜色。需要提供一个颜色值字符串作为参数。
heading 添加一个标题标签在光标处或者所选文字上。需要提供标签名称字符串作为参数(例如:“H1”、“H6”)(IE 和 Safari 不支持) document.execCommand(“heading”, false, “H1”)
insertImage 在插入点插入一张图片(删除选中的部分)。需要一个 URL 字符串作为参数。这个 URL 图片地址至少包含一个字符。空白字符也可以(IE 会创建一个链接其值为 null)
insertOrderedList 在插入点或者选中文字上创建一个有序列表
insertUnorderedList 在插入点或者选中文字上创建一个无序列表。
italic 在光标插入点开启或关闭斜体字。
justifyCenter 对光标插入位置或者所选内容进行文字居中
justifyFull 对光标插入位置或者所选内容进行文本对齐。
justifyLeft 对光标插入位置或者所选内容进行左对齐。
justifyRight 对光标插入位置或者所选内容进行右对齐。
outdent 对光标插入行或者所选行内容减少缩进量。
redo 重做被撤销的操作。
undo 撤销最近执行的命令。
underline 在光标插入点开启或关闭下划线。
unlink 去除所选的锚链接的<a>标签
formatBlock 添加一个 HTML 块式标签在包含当前选择的行,如果已经存在了,更换包含该行的块元素 (在 Firefox 中,BLOCKQUOTE 是一个例外 -它将包含任何包含块元素). 需要提供一个标签名称字符串作为参数。几乎所有的块样式标签都可以使用 (例如。“H1”, “P”, “DL”, “BLOCKQUOTE”). (IE 浏览器仅仅支持标题标签 H1 - H6, ADDRESS,和 PRE,使用时还必须包含标签分隔符 < >, 例如 “<H1>”.) document.execCommand(“formatBlock”, false, “H1”)
enableObjectResizing 启用或禁用图像和其他对象的大小可调整大小手柄。(IE 浏览器不支持)
enableInlineTableEditing 启用或禁用表格行和列插入和删除控件。(IE 浏览器不支持)
enableAbsolutePositionEditor 启用或禁用允许移动绝对定位元素的抓取器。Firefox 63 Beta/Dev Edition 默认禁用此功能

formatBlock是一个自定义的命令,可以通过输入指定的标签名,进行创建标签并包裹选中内容。例如这种:document.execCommand(“formatBlock”, false, “H1”),就可以创建一个H1标签,与 document.execCommand(“heading”, false, “H1”) 效果相同

效果图
这是我创建的富文本效果图,使用了react+antd

工具箱设置为:

const exec = (commandName, value = null) => {
    
    
  var a = document.execCommand(commandName, false, value);
  console.log(a, commandName, value);
};

const tools = [
      {
    
    
        key: 'bold',
        icon: <b>B</b>,
        title: '加粗',
      },
      {
    
    
        key: 'italic',
        icon: <i>I</i>,
        title: '斜体',
      },
      {
    
    
        key: 'underline',
        icon: <u>U</u>,
        title: '下划线',
      },
      {
    
    
        key: 'justifyLeft',
        icon: <AlignLeftOutlined />,
        title: '左对齐',
      },
      {
    
    
        key: 'justifyCenter',
        icon: <AlignCenterOutlined />,
        title: '居中对齐',
      },
      {
    
    
        key: 'justifyRight',
        icon: <AlignRightOutlined />,
        title: '右对齐',
      },
      {
    
    
        key: 'insertOrderedList',
        icon: <OrderedListOutlined />,
        title: '有序列表',
      },
      {
    
    
        key: 'insertUnorderedList',
        icon: <UnorderedListOutlined />,
        title: '无序列表',
      },
      {
    
    
        key: 'createLink',
        icon: <LinkOutlined />,
        title: '超链接',
        onClick() {
    
    
          setModalType('createLink');
        },
      },
      {
    
    
        key: 'formatBlock',
        icon: 'H',
        title: '标题',
        mode: 'hover',
        hoverDom: (
          <ul>
            {
    
    [1, 2, 3, 4, 5, 6].map((item) => (
              <li>
                {
    
    /* <a href="javascript:;" onClick={() => exec('formatBlock', 'H1')}> */}
                <Button onClick={
    
    () => exec('formatBlock', 'H1')}>
                  H{
    
    item}
                </Button>
                {
    
    /* </a> */}
              </li>
            ))}
          </ul>
        ),
      },
]

期间有个问题,创建标签工具时,怎么都无法给选中内容添加H1标签,但是单独给button使用document.execCommand(“heading”, false, “H1”)是可以的,说明了Button可以,div不可以。之后又尝试了一下a标签,如果不加href=“javascript:;”,也不能正常添加,加上后就可以正常添加了。
由此可见,document.execCommand命令不能在 普通文本的节点上使用(该节点不能被选中文本),否则点击文本时,浏览器会认为你开始了新的选择文本动作,导致之前的选中区域失效,此时再去添加H1标签,就会导致选中区域是空的,从而导致不生效。

有兴趣的可以自己尝试一下。感谢您的阅读,有问题可以留言,或者私信。

猜你喜欢

转载自blog.csdn.net/qq_28992047/article/details/127298426