要素过多建议收藏
- 富文本编辑
基本的技术就是在空白
HTML
文件中嵌入一个
iframe
。通过
designMode
属性,可以将这个空白文档变成可以编辑的,实际编辑的则是
<body>
元素
的
HTML
。
designMode
属性有两个可能的值:
"off"
(默认值)和
"on"
。设置为
"on"
时,整个文档
都会变成可以编辑的(显示插入光标),从而可以像使用文字处理程序一样编辑文本,通过键盘将文本
标记为粗体、斜体,等等。
作为
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="richedit" style="height: 100px; width: 100px"></iframe>
<script>
window.addEventListener("load", () => {
frames["richedit"].document.designMode = "on";
});
</script>
以上代码加载之后,可以在页面上看到一个类似文本框的区域。这个框的样式具有网页默认样式,
不过可以通过
CSS
调整。
- 使用 contenteditable
还有一种处理富文本的方式,也是
IE
最早实现的,即指定
contenteditable 属性。可以给页面
中的任何元素指定
contenteditable
属性,然后该元素会立即被用户编辑。这种方式更受欢迎,因为
不需要额外的
iframe
、空页面和
JavaScript
,只给元素添加一个
contenteditable
属性即可,比如:
<div class="editable" id="richedit"
contenteditable
></div>
元素中包含的任何文本都会自动被编辑,元素本身类似于
<textarea>
元素。通过设置
contentEditable
属性,也可以随时切换元素的可编辑状态:
let div = document.getElementById("richedit");
richedit.contentEditable = "true";
contentEditable
属性有
3
个可能的值:
"true"
表示开启,
"false"
表示关闭,
"inherit"
表示
继承父元素的设置(因为在
contenteditable
元素内部会创建和删除元素)。
IE
、
Firefox
、
Chrome
、
Safari
和
Opera
及所有主流移动浏览器都支持
contentEditable
属性。
- 与富文本交互
与富文本编辑器交互的主要方法是使用
document.execCommand()
。这个方法在文档上执行既定
的命令,可以实现大多数格式化任务。
document.execCommand()
可以接收
3
个参数:要执行的命令、
表示浏览器是否为命令提供用户界面的布尔值和执行命令必需的值(如果不需要则为
null
)。为跨浏览
器兼容,第二个参数应该始终为
false
,因为
Firefox
会在其为
true
时抛出错误。
不同浏览器支持的命令也不一样。下表列出了最常用的命令。
?
剪贴板相关的命令与浏览器关系密切。虽然这些命令并不都可以通过
document.execCommand()
使用,但相应的键盘快捷键都是可以用的。
这些命令可以用于修改内嵌窗格(
iframe
)中富文本区域的外观,如下面的例子所示:
//
在内嵌窗格中切换粗体文本样式
frames["richedit"].document.execCommand("bold", false, null);
//
在内嵌窗格中切换斜体文本样式
frames["richedit"].document.execCommand("italic", false, null);
//
在内嵌窗格中创建指向
www.wrox.com
的链接
frames["richedit"].document.execCommand("createlink", false,
"http://www.wrox.com");
//
在内嵌窗格中为内容添加
<h1>
标签
frames["richedit"].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>");
?
注意,即使命令是所有浏览器都支持的,命令生成的
HTML
通常差别也很大。例如,为选中文本
应用
bold
命令在
IE
和
Opera
中会使用
<strong>
标签,在
Safari
和
Chrome
中会使用
<b>标签,而在Firefox
中会使用
<span>
标签。在富文本编辑中,不能依赖浏览器生成的
HTML,因为命令实现和格式 转换都是通过
innerHTML
完成的。
还有与命令相关的其他一些方法。第一个方法是
queryCommandEnabled()
,此方法用于确定对当
前选中文本或光标所在位置是否可以执行相关命令。它只接收一个参数,即要检查的命令名。如果可编 辑区可以执行该命令就返回
true
,否则返回
false
。来看下面的例子:
let result = frames["richedit"].document.queryCommandEnabled("bold");
以上代码在当前选区可以执行
"bold"
命令时返回
true
。不过要注意,
queryCommandEnabled()
返回
true
并不代表允许执行相关命令,只代表当前选区适合执行相关命令。在
Firefox
中,
queryCommandEnabled("cut")
即使默认不允许剪切也会返回
true
。
另一个方法
queryCommandState()
用于确定相关命令是否应用到了当前文本选区。例如,要确定
当前选区的文本是否为粗体,可以这样:
let isBold = frames["richedit"].document.queryCommandState("bold");
如果之前给文本选区应用过
"bold"
命令,则以上代码返回
true
。全功能富文本编辑器可以利用这
个方法更新粗体、斜体等按钮。
最后一个方法是
queryCommandValue()
,此方法可以返回执行命令时使用的值(即前面示例的
execCommand()
中的第三个参数)。如果对一段选中文本应用了值为
7
的
"fontsize"命令,则如下代 码会返回
7
:
let fontSize = frames["richedit"].document.queryCommandValue("fontsize");
这个方法可用于确定如何将命令应用于文本选区,从而进一步决定是否需要执行下一个命令。
- 富文件选择?
在内嵌窗格中使用
getSelection()
方法,可以获得富文本编辑器的选区。这个方法暴露在
document
和
window
对象上,返回表示当前选中文本的
Selection
对象。每个
Selection
对象都拥
有以下属性。
?
anchorNode
:选区开始的节点。
?
anchorOffset
:在
anchorNode
中,从开头到选区开始跳过的字符数。
?
focusNode
:选区结束的节点。
?
focusOffset
:
focusNode
中包含在选区内的字符数。
?
isCollapsed
:布尔值,表示选区起点和终点是否在同一个地方。
?
rangeCount
:选区中包含的
DOM
范围数量。
Selection
的属性并没有包含很多有用的信息。好在它的以下方法提供了更多信息,并允许操作
选区。
?
addRange(
range
)
:把给定的
DOM
范围添加到选区。
?
collapse(
node, offset
)
:将选区折叠到给定节点中给定的文本偏移处。
?
collapseToEnd()
:将选区折叠到终点。
?
collapseToStart()
:将选区折叠到起点。
?
containsNode(
node
)
:确定给定节点是否包含在选区中。
?
deleteFromDocument()
:从文档中删除选区文本。与执行
execCommand("delete", false,
null)
命令结果相同。
?
extend(
node, offset
)
:通过将
focusNode
和
focusOffset
移动到指定值来扩展选区。
?
getRangeAt(
index
)
:返回选区中指定索引处的
DOM
范围。
?
removeAllRanges()
:从选区中移除所有
DOM
范围。这实际上会移除选区,因为选区中至少
要包含一个范围。
?
removeRange(
range
)
:从选区中移除指定的
DOM
范围。
?
selectAllChildren(
node
)
:清除选区并选择给定节点的所有子节点。
?
toString()
:返回选区中的文本内容。
Selection
对象的这个方法极其强大,充分利用了
DOM
范围来管理选区。操纵
DOM
范围可以实
现比
execCommand()
更细粒度的控制,因为可以直接对选中文本的
DOM 内容进行操作。来看下面的 例子:
let selection = frames["richedit"].getSelection();
// 取得选中的文本
let selectedText = selection.toString();
// 取得表示选区的范围
let range = selection.getRangeAt(0);
// 高亮选中的文本
let span = frames["richedit"].document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);
以上代码会在富文本编辑器中给选中文本添加黄色高亮背景。实现方式是在默认选区使用
DOM
范
围,用
surroundContents()
方法给选中文本添加背景为黄色的
<span>
标签。
getSelection()
方法在
HTML5
中进行了标准化,
IE9
以及
Firefox
、
Safari
、
Chrome
和
Opera
的所
有现代版本中都实现了这个方法。
IE8
及更早版本不支持
DOM
范围,不过它们允许通过专有的
selection
对象操作选中的文本。如
本章前面所讨论的,这个
selection
对象是
document 的属性。要取得富文本编辑器中选中的文本, 必须先创建一个文本范围,然后再访问其
text
属性:
let range = frames["richedit"].document.selection.createRange();
let selectedText = range.text;
使用
IE
文本范围执行
HTML
操作不像使用
DOM
范围那么可靠,不过也是可以做到的。要实现与
使用
DOM
范围一样的高亮效果,可以组合使用
htmlText
属性和
pasteHTML()
方法:
let range = frames["richedit"].document.selection.createRange();
range.pasteHTML(
'<span style="background-color:yellow">${range.htmlText}</span>');
以上代码使用
htmlText
取得了当前选区的
HTML
,然后用一个
<span>
标签将其包围起来并通过
pasteHTML()
再把它插入选区中。