富文本编辑,即所见即所得(What You See Is What You Get)。这个技术的本质是在页面中嵌入一个包含空 HTML 页面的 iframe。通过 designMode 属性(设置为 on),这个页面就可以被编辑,编辑对象是这个页面的 <body> 元素的 HTML 代码。
iframe 中使用一个简单的 HTML 页面就可以作为内容:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Blank Page for Rich Text Editing</title> </head> <body> <script type="text/javascript"> </script> </body> </html>只有在页面完全加载后才能设置 designMode 属性,所以要使用 onload 事件来设置这一属性:
<iframe name="richedit" style="height: 100px;width:100px;" src="blank.htm"></iframe> <script type="text/javascript"> EventUtil.addHandler(window, "load", function () { frames["richedit"].document.designMode = "on"; }) </script>打开后会看到一个类似文本框的可编辑区域。
把 contenteditable 属性设置给页面中的任何一个元素后,用户就可以立即编辑这个元素咯,是不是很方便呀:
<div class="editable" id="richedit" contenteditable></div>在某个元素上设置 contenteditable 属性,也可以打开或关闭编辑模式:
var div = document.getElementById("richedit"); richedit.contenteditable = "true";contenteditable 属性有三个值:
值说明true打开false关闭inherit继承自父元素五大浏览器都支持 contenteditable 属性。移动设备的浏览器中,iOS 5+ 的 Safari 和 Android 3+ 的 Webkit 也支持这个属性。
使用 document.execCommand() 可以与富文本编辑器进行交互。它接受 3 个参数:要执行的命令名称、是否为当前命令提供用户界面(为保证跨浏览器,通常设置为 false)以及命令参数。下面列出支持最多的命令:
命令值(第 3 个参数)说明backcolor颜色字符串设置文档的背景色。boldnull将选择的文本转换为粗体。copynull将选择的文本复制到剪贴板。createlinkURL 字符串将选择的文本转换为链接,然后指向指定的 URL。cutnull将选择的文本剪贴到剪贴板。deletenull删除选择的文本。fontname字体名称将选择的文本改为指定的字体。fontsize1 ~ 7将选择的文本改为指定的字体大小。forecolor颜色字符串将选择的文本改为指定的颜色。formatblock需要包围当前文本块的 HTML 标签使用指定的 HTML 标签来包裹指定的文本块。indentnull缩进文本。inserthorizontalrulenull在光标处插入一个 <hr> 元素。insertimage图像的 URL在光标处插入一个图像。insertorderedlistnull在光标处插入一个<ol> 元素。insertunorderedlistnull在光标处插入一个<ul> 元素。insertparagraphnull在光标处插入一个<p> 元素。italicnull将选择的文本改为斜体。justifycenternull在光标处的文本块居中对齐。justifyleftnull在光标处的文本块左对齐。outdentnull减少缩进。pastenull将剪贴板中的内容粘贴到选择的文本。removeformatnull移除包围当前文本块的 HTML 标签,这是撤销 formatblock 命令的操作。selectallnull选中所有文本。underlinenull为选中的文本添加下划线。unlinknull移除文本链接,这是撤销 createlink 命令的操作。注意:与剪贴板相关的命令在不同的浏览器中差别很大!Opera 没有实现任何与剪贴板相关的命令,Firefox 会在默认情况下禁止这些命令。Safari 和 Chrome 实现了 cut 和 copy,但没有实现 paste。虽然不能使用 document.execCommand() 执行这些命令,但可以通过快捷键来实现同样的功能。
可以使用这些命令来改变富文本区域的外观:
<form method="post" action="javascript:alert('Form submitted!')" id="myForm"> <div id="divSimple"> <input type="button" value="Bold"> <input type="button" value="Italic"> <input type="button" value="createLink"> <input type="button" value="h1"> <input type="button" value="enabled"> <input type="button" value="state"> <input type="button" value="commandValue"> <input type="button" value="setBackground"> <!--<input type="button" value="Underline">--> <!--<input type="button" value="Indent">--> <!--<input type="button" value="Outdent">--> <!--<input type="button" value="Copy">--> <!--<input type="button" value="Cut">--> <!--<input type="button" value="Paste">--> </div> <div id="richedit" style="height: 100px;width: 300px;border: dashed" contenteditable></div> <button type="sumbit">sumbit</button> <input type="hidden" id="comments"> </form> ``` ``` <script type="text/javascript"> (function () { var simple = document.getElementById("divSimple"); EventUtil.addHandler(simple, "click", function (event) { event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); if (target.type = "button") { switch (target.value) { case "Bold"://粗体 // document.execCommand(target.value.toLowerCase(), false, null); document.execCommand("bold", false, null); break; case "Italic"://斜体 document.execCommand("italic", false, null); break; case "createLink"://创建链接 document.execCommand("createlink", false, "http://www.163.com"); break; case "h1"://格式化为 h1 document.execCommand("formatblock", false, "<h1>"); break; case "enabled"://是否可以针对当前选择的文本执行某个命令 console.log(document.queryCommandEnabled("bold")); break; case "state"://是否已将指定命令应用到了选择的文本 console.log(document.queryCommandState("bold")); break; case "commandValue"://取得执行命令时传入的值 console.log(document.queryCommandValue("fontsize")); break; case "setBackground"://添加黄色背景(富文本选区操作) var selection = document.getSelection(); //取得选择的文本 var selectedText = selection.toString(); //取得代表选区的范围 var range = selection.getRangeAt(0); //突出显示已经选择的文本 var span = document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span); break; } } }); })(); </script>注意:虽然所有的浏览器都支持这些命令,但它们生成的 HTML 文本并不相同!比如执行 bold 命令后,IE 和 Opera 会使用 <strong> 标签包围文本,而 Safari 和 Chrome 使用的是 <b> 标签,在 Firefox 中使用的是 <span> 标签!
queryCommandEnabled() 方法是用来检查某个命令是否适用于当前选中的文本,或者是否能在当前光标处执行该命令。它接受一个参数,即要检测的命令。返回布尔值:
var result = frames["richedit"].document.queryCommandEnabled("bold");
这个命令其实并不可靠,比如在 Firefox 中禁用剪切操作的情况下,这个命令仍会返回 false。
queryCommandState() 方法用于确定某个命令是否已经应用到所选中的文本:
var result = frames["richedit"].document.queryCommandState("bold");
那些富文本编辑器就是根据这个方法返回的值来更新粗体、斜体的按钮状态的。
queryCommandValue() 可以取得执行命令时传入的值(就是 document.execCommand() 方法的第 3 个值):
var fontSize = frames["richedit"].document.queryCommandValue("fontsize");//7
# 3 富文本选区
使用 iframe 的 getSelection() 方法可以获取实际选中的文本。它会返回当前选中文本的 Selection 对象。每个 Selection 对象都有这些属性:
属性名说明anchorNode选区起点所在的节点。anchorOffset到达选区起点之前所跳过的 anchorNode 的字符数量。focusNode选区终点所在的节点。isCollapsed选区起点与终点是否重合。rangeCount选区中包含的 DOM 范围的数量。这些属性其实没有多少价值,我们再看看 Selection 对象所拥有的方法:
方法名说明addRange(range)把指定的 DOM 范围添加到选区中。collpase(node, offset)把选区折叠到指定节点中相应偏移量位置。collapseToEnd()把选区折叠到终点。collapseToStart()把选区折叠到起点。deleteFromDocument()从文档中删除选区中的文本,这与 执行 document.execCommand(“delete”, false, null) 命令的结果相同。extend(node offset)把 focusNode 和 focusOffset 移动到指定偏移量来扩展选区。getRangeAt(index)返回索引对应选区中的 DOM 范围。removeAllRanges()从选区中移除所有 DOM 范围,没有了范围,选区也会被移除。removeRange(range)从选区中移除指定的 DOM 范围。selectAllChildren(node)清除选区,然后选择指定节点的所有节点。toString()返回选区所包含的文本内容。这些方法很实用,可以使用它们来管理选区:
var selection = document.getSelection(); //取得选择的文本 var selectedText = selection.toString(); //取得代表选区的范围 var range = selection.getRangeAt(0); //突出显示已经选择的文本 var span = document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span);上面这段代码会把被选择的文本添加上黄色的背景:
因为富文本编辑使用的是 iframe,所以它并不属于表单。所以自然不会被自动提交给服务器,因此需要手工处理。可以添加一个隐藏字段,把它的值设置为从 iframe 中提取出的 富文本内容:
<input type="hidden" id="comments"> ... var form = document.getElementById("myForm"); EventUtil.addHandler(form, "submit", function (event) {//把富文本域的值添加到表单 event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); target.elements["comments"].value = document.getElementById("richedit").innerHTML; console.log(target.elements["comments"].value); })