一步步教你实现富本文编辑器(第一部分)
先打造好毛坯,添加上各位按钮与下拉选择框,如字体、字号、对齐、斜体、加粗、编号、缩进、背景色、前景色……为了方便我们按制样式,按钮是用span模拟的。
<!doctype html> <html dir="ltr" lang="zh-CN"> <head> <meta charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <style type="text/css"> #editor{ float:left; width:380px;background:#D5F3F4;padding-left:10px; } #editor span.button{ display:block;float:left;border: 1px solid #CCC;margin:1px 5px 1px 0px ;color: #000; background: #D0E8FC;width:40px;height:20px;text-align:center; } #editor select{ display:block; float:left;height:20px;width:60px;margin-right:5px;} textarea {width:382px;height:100px;} </style> <title>富文本编辑器</title> </head> <body> <div id="editor"> <span class="button">加粗</span> <span class="button">斜体</span> <span class="button">下划</span> <span class="button">居中</span> <span class="button">居左</span> <span class="button">居右</span> <span class="button">悬挂</span> <span class="button">缩进</span> <span class="button">无序</span> <span class="button">有序</span> <select> <option value="SimSun">宋体</option> <option value="LiSu">隶书</option> <option value="KaiTi_GB2312">楷体</option> <option value="YouYuan">幼圆</option> <option value="SimHei">黑体</option> <option value="Microsoft YaHei">雅黑</option> <option value="Comic Sans MS">Comic Sans MS</option> </select> <select> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> <select> <option style="color:#000000" value="#000000">■■</option> <option style="color:#FF8080" value="#FF8080">■■</option> <option style="color:#FFFF00" value="#FFFF00">■■</option> <option style="color:#80FF00" value="#80FF00">■■</option> <option style="color:#00FFFF" value="#00FFFF">■■</option> <option style="color:#0000FF" value="#0000FF">■■</option> <option style="color:#FF00FF" value="#FF00FF">■■</option> </select> <select> <option style="color:#000000" value="#000000">■■</option> <option style="color:#FF8080" value="#FF8080">■■</option> <option style="color:#FFFF00" value="#FFFF00">■■</option> <option style="color:#80FF00" value="#80FF00">■■</option> <option style="color:#00FFFF" value="#00FFFF">■■</option> <option style="color:#0000FF" value="#0000FF">■■</option> <option style="color:#FF00FF" value="#FF00FF">■■</option> </select> </div> <br style="clear:both"/> <textarea></textarea> </body> </html>
然后我们就可以加入行为层代码了。富文本编辑器用到一个非常关键的脚本document.execCommand( command, showUI, value )。
我们把各命令的参数放到按钮的title中,并在onclick与onchange时调用它们。
<div id="editor"> <span class="button" title="bold">加粗</span> <span class="button" title="italic">斜体</span> <span class="button" title="underline">下划</span> <span class="button" title="justifycenter">居中</span> <span class="button" title="justifyleft">居左</span> <span class="button" title="justifyright">居右</span> <span class="button" title="outdent">悬挂</span> <span class="button" title="indent">缩进</span> <span class="button" title="insertunorderedlist">无序</span> <span class="button" title="insertorderedlist">有序</span> <select title="fontname"> <!-- 省略 --> </select> <select title="fontsize"> <!-- 省略 --> </select> <select title="forecolor"> <!-- 省略 --> </select> <select title="backcolor"> <!-- 省略 --> </select> </div>
window.onload = function(){ var editor = document.getElementById("editor"); var buttons = editor.getElementsByTagName("span"); var selects = editor.getElementsByTagName("select"); for(var i = 0,l= buttons.length;i<l;i++){ buttons[i].onclick = new function(){ var button=buttons[i]; return function(){ document.getElementById("exe").innerHTML = "调用了"+button.getAttribute("title")+"命令"; } }; }; for(i=0,l=selects.length;i<l;i++){ selects[i].onchange = new function(){ var select = selects[i]; return function(){ document.getElementById("exe").innerHTML = "调用了"+select.getAttribute("title")+"命令,并传入了"+ select.options[select.selectedIndex].value+"参数!"; }; }; }; }
好了,那么怎么样编辑文本区(textarea)的文字呢?错,文本区的文字本身就可以编辑,就是怎么也不可能显示其编辑后的效果。我们通常是在div与iframe中编辑。要想在DIV中编辑,设置其contentEditable = "true",若iframe,还可以用designMode="on"。通常人们都是用ifame,这样做当然有它的道理,但一开始,照顾初心者,我们用div实现一下吧。
<div id="workaround"> </div>
#workaround {width:382px;height:100px;border:1px solid #0065FD;}
那么怎么获得我们选中的文字?不,这个提法也不对,我们不是对文字直接进行操作,而对能对这些文字进行操作的对象进行操作……实在太拗口了!这就是传说中的Range对象了!
var getRangeObject = function(){ if(document.implementation.hasFeature("Range", "2.0")){ return document.createRange();//W3C }else{ return document.selection.createRange();//IE } }
但上面这个函数离我们的目标有些差距,无错,document.selection.createRange.execCommand('bold')就可以把我们选出中的文字加粗了,但火狐那边就不是这回事!这与它们的执行模式有关,当我们选中一段文字时,IE会立即把它们放进Range对象中,但符合W3C标准的游览器不会,它是空的,虽然我们手动加入……手动加入就手动加入吧,自己动手,丰衣足食!
var getRangeObject = function() { if (window.getSelection){//W3C var range = document.createRange(), selection = window.getSelection(); range.setStart(selection.anchorNode, selection.anchorOffset); range.setEnd(selection.focusNode, selection.focusOffset); return range; }else { //IE return document.selection.createRange(); } }
但是还是失败了,究其原因,标准的Range对象(有关Range的介绍)是没有execCommand()方法。而IE的Range对象,说到底是TextRange对象,两者有很大差别。那怎么办?先放一放它,先实现了IE的再说,以后我们用iframe的document来执行execCommand()便是!
window.onload = function(){ var editor = document.getElementById("editor"); var buttons = editor.getElementsByTagName("span"); var selects = editor.getElementsByTagName("select"); var workaround = document.getElementById("workaround"); workaround.contentEditable = "true"; for(var i = 0,l= buttons.length;i<l;i++){ buttons[i].onclick = new function(){ var command=buttons[i].getAttribute("title"); return function(){ document.selection.createRange().execCommand(command);//IE only } }; }; for(i=0,l=selects.length;i<l;i++){ selects[i].onchange = new function(){ var select = selects[i]; return function(){ var command = select.getAttribute("title"), value = select.options[select.selectedIndex].value; document.selection.createRange().execCommand(command,false,value);//IE only }; }; }; }
注意,我们在按扭上面绑定了一个IE私有属性unselectable,并设置为on,这是防止当我们点击按钮时,TextRange对象因为选择对象转移,把原来选择的文本丢失了。其他游览器也有相似的功能,如safari,chrome为onselectstart="return false;" ,火狐为 style="-moz-user-select:none;"。
虽然兼容火狐失败,但作为副产品,搞了这个
下一部分,我们将改用iframe实现富本编辑器,处理众多的兼容问题!