富文本编辑器(Rich Text Editor)是在网页上应用的一种所见即所得的文本编辑器,是 Web 利用开发中很常见的需要。

富文本实现

在 HTML 文档上共有 2 中形式实现富文本编辑器。一种是应用 iframe,另一种是应用 contenteditable 属性指定 HTML 文档元素。

iframe

第一种形式是应用 iframe 标签。

在空白的 HTML 文档中嵌入一个 iframe,并将 designMode 属性设置为 "on",文档就会变成可编辑的,理论编辑的则是 <body> 元素的 HTML,默认值是 "off"。文档变成可编辑后,就能够像应用文字处理程序一样编辑文本,通过键盘将文本标记为粗体、斜体等等。

作为 iframe 源的是一个非常简单的空白 HTML 页面。上面是一个例子:

<!DOCTYPE html><html><head>    <title>Blank Page for Rich Text Editing</title></head><body></body></html>

这个页面会像其余任何页面一样加载到 iframe 里。为了能够编辑,必须将文档的 designMode 属性设置为 "on"。不过,只有在文档齐全加载之后能够设置。在这个蕴含页面内,须要应用 onload 事件处理程序在适当机会设置 designMode,如上面的例子所示:

<iframe name="editor" style="height: 100px; width: 100px"></iframe><script>    window.addEventListener("load", () => {        frames["editor"].document.designMode = "on";    });</script>

以上代码加载之后,能够在页面上看到一个相似文本框的区域。这个框的款式具备网页默认款式,不过能够通过 CSS 调整。

contenteditable

第二种形式是应用 contenteditable 属性指定 HTML 文档中的元素。该形式是 IE 最早实现的。应用形式是在一个元素上增加 contenteditable 属性并设置为 true 或者空字符串"",而后该元素会立刻被用户编辑。如下所示:

<div class="editor" id="editorId" contenteditable="true"></div>

元素中蕴含的任何文本都会主动被编辑, 元素自身相似于<textarea> 元素。通过设置contentEditable 属性,也能够随时切换元素的可编辑状态:

let div = document.getElementById("editorId");richedit.contentEditable = "true";

contentEditable 属性有3 个可能的值:"true" 示意开启,"false" 示意敞开,"inherit" 示意继承父元素的设置。支流浏览器都反对 contentEditable 属性。

留神:contenteditable 是一个十分多才多艺的属性。比方,拜访伪 URL data:text/html, <html contenteditable>能够把浏览器窗口转换为一个记事本。这是因为这样会长期创立 DOM 树并将整个文档变成可编辑区域。

与富文本交互

下面讲到了如何在 HTML 文档中实现富文本编辑器,而当初须要理解要应用什么形式与富文本编辑器交互。document 提供了 execCommand() 办法,该办法会影响应用 contentEditable 属性实现可编辑区域的元素。办法阐明如下所示:

execCommand(commandId: string, showUI?: boolean, value?: string): boolean;
  • commandId:参数是 string 值,示意要执行的命令。上面会列出可用命令。
  • showUI:参数是 boolean 的可选值,示意浏览器是否为命令提供用户界面,个别为 false。为兼容的话,该参数须要始终为 false,因为 Mozilla 没有实现,会在其为 true 时抛出谬误。
  • value:参数是 string 的可选值,是一些命令须要额定的参数,默认为 null

该办法执行后,会返回 boolean 值,如果是 false,示意操作不被反对或未被启用。

留神:在调用一个命令前,不要尝试应用返回值去校验浏览器的兼容性

不同浏览器反对的命令也不一样。下标列出了最罕用的命令。

命令作用可选值
backColor设置文档背景色彩。在styleWithCss模式下,则只影响容器元素的背景色彩。色彩值<color>字符串(IE应用这个命令设置文本背景色)
bold切换选中文本的粗体款式null
copy将选中内容复制到剪贴板null
createLink将选中内容转换为指向给定URL的链接URL链接值,至多蕴含一个字符
cut将选中内容剪切到剪贴板null
delete删除选中的内容null
fontName将选中文本改为应用指定字体字体名(例如:"Arial")
fontSize将选中文本改为指定字体大小提供HTML字体尺寸(1-7)
foreColor将选中文本改为指定色彩色彩值<color>字符串
formatBlock将选中文本蕴含在指定的HTML标签中提供HTML标签,如<h1>
indent缩进文本null
insertHorizontalRule在光标地位插入<hr>元素null
insertImage在光标地位插入图片图片的URL链接
insertOrderedList在光标地位插入<ol>元素null
insertunorderedlist在光标地位插入<ul>元素null
insertParagraph在光标地位插入<p>元素null
italic切换选中文本的斜体款式null
justifyCenter在光标地位或者所选内容进行文字居中null
justifyFull在光标地位或者所选内容进行文本对齐null
justifyLeft在光标地位或者所选内容进行左对齐null
justifyRight在光标地位或者所选内容进行右对齐null
outdent减小缩进null
paste在光标地位粘贴剪贴板内容,如果有被选中的内容,会被替换null
redo重做被撤销的操作null
removeFormat对所选内容去除HTML格局。这是formatBlock的反操作null
selectAll选中编辑区里的全部内容null
strikeThrough切换删除线null
subscript切换下角标null
superscript切换上角标null
underline切换下划线null
undo撤销最近执行的命令null
unlink取出所选链接的<a>标签null
styleWithCSS用这个取代useCSS命令。切换应用HTML tags还是CSS来生成标记。Boolean值,false应用CSS,true应用HTML

剪贴板相干的命令与浏览器关系密切。尽管这些命令并不都能够通过 document.execCommand() 应用,但相应的键盘快捷键都是能够用的。

这些命令能够用于批改 iframe 中富文本区域的外观,如上面的例子所示:

// 在内嵌窗格中切换粗体文本款式frames["editor"].document.execCommand("bold", false, null);// 在内嵌窗格中切换斜体文本款式frames["editor"].document.execCommand("italic", false, null);// 在内嵌窗格中创立指向www.wrox.com 的链接frames["editor"].document.execCommand("createlink", false, "http://www.wrox.com");// 在内嵌窗格中为内容增加<h1>标签frames["editor"].document.execCommand("formatblock", false, "<h1>");

同样的办法也能够用于页面中增加了 contenteditable 属性的元素,只不过要应用以后窗口而不是内嵌窗格中的 document 对象:

// 切换粗体文本款式document.execCommand("bold", false, null);// 切换斜体文本款式document.execCommand("italic", false, null);// 创立指向www.wrox.com 的链接document.execCommand("createlink", false, "http://www.wrox.com");// 为内容增加<h1>标签document.execCommand("formatblock", false, "<h1>");

留神:应用bold的命令在浏览器中生成的 HTML 差异很大。如在 IE 和 Opera 中应用<strong>标签,在 Safari 和 Chrome 中应用<b>标签,在 Firefox 中应用 <span> 标签。

document 中提供了 queryCommandEnabled() 办法:

queryCommandEnabled(commandId: string): boolean;
  • commandId:接管 string 类型参数,是待查问是否可用的命令。

该办法用于确定对以后选中文本或光标所在位置是否能够执行相干命令。true 指令可用,false 不可用。如下所示:

let result = document.queryCommandEnabled("selectAll");

但要留神,返回 true 并不代表容许执行相干命令,只代表以后选区适宜执行相干命令。在 Firefox 中,queryCommandEnabled("cut") 即便默认不容许剪切也会返回 true

document 还提供 queryCommandState() 办法:

queryCommandState(commandId: string): boolean;
  • commandId:参数是要确定的命令。

该办法用于确定相干命令是否利用到了以后文本选区。如下所示:

let isBold = document.queryCommandState("selectAll");

富文本编辑器能够利用这个办法更新粗体、斜体等按钮。

在介绍一下 queryCommandValue() 办法:

queryCommandValue(commandId: string): string;

这个办法用于返回执行命令时应用的值,参考 execCommand() 办法应用的第三个参数。如下所示,如果一段选中文本利用了值为 5 的 "fontsize" 命令,应用该办法会返回 5:

let fontSize = document.queryCommandValue("fontsize");

这个办法可用于确定如何将命令利用于文本选区,从而进一步决定是否须要执行下一个命令。

富文件选区

Selection 对象示意用户选中的文本范畴或光标的地位,它代表页面中的文本选区。能够应用 windowdocument 对象调用 getSelection() 办法获取文本选区。Selection 对象领有以下属性。

  • anchorNode:只读属性,形容选区终点所在的节点。
  • anchorOffset:只读属性,返回的是选区终点在 anchorNode 中的地位偏移量 。
  • focusNode:只读属性,返回选区起点所在的节点。
  • focusOffset:只读属性,返回的是选区起点在 focusNode 中的地位偏移量。
  • isCollapsed:只读属性,返回boolean值,用来示意选区终点和起点是否在同一个地位。
  • rangeCount:只读属性,返回选区所蕴含的 DOM 范畴数量。

Selection 的属性并没有蕴含很多有用的信息。好在它的以下办法提供了更多信息,并容许操作选区。

  • addRange(range):把给定的 DOM 范畴增加到选区。
  • collapse(node, offset):将选区折叠到给定节点中给定的文本偏移处。
  • collapseToEnd():将选区折叠到起点。
  • collapseToStart():将选区折叠到终点。
  • containsNode(node):判断给定节点是否蕴含在选区中。
  • deleteFromDocument():从文档中删除选区内容。与执行 execCommand("delete", false, null) 命令后果雷同。
  • extend(node, offset):通过将 focusNodefocusOffset 挪动到指定值来扩大选区。
  • getRangeAt(index):返回选区中指定索引处的 DOM 范畴。
  • removeAllRanges():将所有的区域都从选区中移除。
  • removeRange(range):从选区中移除指定的 DOM 范畴。
  • selectAllChildren(node):革除选区并抉择给定节点的所有子节点。
  • toString():返回选区中的纯文本内容。

上面介绍一个例子,是应用 Selection 对象实现选中文本高亮:

function highlight() {    let selection = document.getSelection();    // 获得示意选区的范畴    let range = selection.getRangeAt(0);    // 高亮选中的文本    let span = document.createElement("span");    span.style.backgroundColor = "yellow";    // 给选中文本增加背景为黄色的<span>标签    range.surroundContents(span);}

成果如下:

通过表单提交富文本

因为富文本编辑不是在表单控件中实现,这意味着要将富文本编辑后果提交给服务器,就要手动进行。咱们会在表单中增加一个 type="hidden" 的字段,在提交表单时,通过监听器,从元素中提取出 HTML 并插入暗藏字段中。如下所示:

// form 实例是`<form>` 元素,能够应用DOM获取form.addEventListener("submit", (event) => {    let target = event.target;    target.elements["content"].value = frames["editor"].document.body.innerHTML;});

上述从编辑器中获取了 HTML 后,将其插入名为 content 的字段中。上面是对于 contenteditable 元素实现的形式:

这里,代码应用文档主体的 innerHTML 属性获得了 iframe 的 HTML,而后将其插入名为 "comments" 的表单字段中。这样做能够确保在提交表单之前给表单字段赋值。如果应用 submit() 办法手工提交表单,那么要留神在提交前先执行上述操作。对于 contenteditable 元素,执行这一操作的代码是相似的:

// form 实例是`<form>` 元素,能够应用DOM获取form.addEventListener("submit", (event) => {    let target = event.target;    target.elements["content"].value = document.getElementsByClassName("editor")[0].innerHTML;});

总结

本文介绍了实现富文本编辑器有两种形式:应用 iframecontenteditable 属性。介绍了应用 document.execCommand() 办法来实现加粗、斜体款式等性能,还有一些相应的性能。而且富文本编辑的内容要上传到服务器,还要将内容先复制到表单中的一个字段上,而后在提交。

更多内容请关注公众号「海人为记