一步步教你实现富本文编辑器(第一部分)
先打造好毛坯,添加上各位按钮与下拉选择框,如字体、字号、对齐、斜体、加粗、编号、缩进、背景色、前景色……为了方便我们按制样式,按钮是用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实现富本编辑器,处理众多的兼容问题!
浙公网安备 33010602011771号