富文本编辑器
最后更新于:2022-04-01 23:54:04
## 富文本编辑器
**1、富文本编辑器简介**
富文本编辑(WYSIWYG(What You See Is What You GET,所见即所得))。
最先的富文本编辑,就是在页面中嵌入一个包含空HTML页面的`iframe`,然后通过设置`designMode`属性,这个空白的HTML页面就可以编辑了,编辑对象则是该页面``元素的HTML代码。
designMode属性有两个可能的值:“off”和“on”,默认为“off”。
给iframe指定一个非常简单的HTML页面作为编辑框:
```
Edit
```
要将其设置成可编辑,不是在iframe页面内,而是它嵌入的那个页面,而且必须等待页面完全加载后才能设置`designMode`属性:
```
window.onload = function(){
window.frames['richedit'].document.designMode = 'on';
}
```
等到上面的代码执行完,就可以使用可编辑区了。
**1.1 使用contenteditable属性**
可以给页面中的任何元素添加`contenteditable`属性,使其成为可编辑区:
```
```
当然,也可以通过JavaScript设置:
```
var richedit = document.getElementById('richedit');
richedit.contentEditable = 'true';
```
**1.2 获取编辑区里的HTML内容**
```
// iframe
frames['richedit'].document.body.innerHTML
// 设置contenteditable的元素
richedit.innerHTML
```
**2 富文本选区**
在富文本编辑器中,使用框架(iframe)的`getSelection()`方法,可以确定实际选择的文本,这个方法是window对象和document对象是属性,调用它会返回一个表示当前选择文本的Selection对象。
每个`Selection`对象可能包含一个或多个`Range`对象。
`Range` 对象表示文档的连续范围区域,简单的说就是高亮选区。一个Range的开始点和结束点位置任意,开始点和结束点也可以是一样的(空Range)。最常见的就是用户在浏览器窗口中用鼠标拖动选中的区域。
不过,不同的浏览器,`Range`对象是不一样的,在Chrome、Mozilla、Safari等主流浏览器上,Range属于`selection`对象(表示range范围),而在IE下,Range属于`TextRange`对象(表示文本范围)。
在下面的所有列子中,皆以selection对象为主,同时会加上textRange对象的兼容代码。
**2.1 拖动选择获取**
每一个浏览器窗口都有一个selection(或text Range)对象,我们可以通过`window.getSelection()`方法来获取:
```
var selectedRange;
function saveSelection(){
if(window.getSelection){
/*主流的浏览器,包括chrome、Mozilla、Safari*/
return window.getSelection();
}else if(document.selection){
/*IE下的处理*/
return document.selection.createRange();
}
return null;
};
```
注意:标准dom是从window中获取selection对象,而ie是从document对象中获取。
实例(可以试试在不同浏览器下的执行,点击里面的按钮btn1):Demo
**2.2 优化获取代码**
一个selection对象有可能不是只有一个Range对象,有可能有多个,每一个Range对象代表用户鼠标所选取范围内的一段连续区域。(在Firefox中,可以通过 ctrl键可以选取多个连续的区域,因此在Firefox中一个selection对象有多个range对象,在其他浏览器中,用户只能选取一段连续的区 域,因此只有一个range对象。)
如何获取某个Range对象呢?我们可以通过selection对象的getRangeAt方法来获取:
```
range = window.getSelection().getRangeAt(index)
```
`getRangeAt()`方法接受一个参数,代表该Range对象的序列号,也可以说你拖动选择的顺序号,它的值有如下几种情况:
- 当用户没有按下鼠标时候,该参数的值为0.
- 当用户按下鼠标的时候,该参数值为1.
- 当用户使用鼠标同时按住ctrl键时选取了一个或者多个区域时候,该参数值代表用户选取区域的数量。
- 当用户取消区域的选取时,该属性值为1,代表页面上存在一个空的Range对象;
要获取Range对象,一般我们会判断是否有Range对象,我们可以通过selection对象的rangeCount属性(类似数组的length,返回Range对象的数量)来判断是否有多个Range对象,然后再去调用getRangeAt()方法。
对于富文本编辑器来说,一般情况下,我们只需要一个选择区域(Range对象),优化后的代码如下:
```
function saveSelection(){
if(window.getSelection){
/*主流的浏览器,包括chrome、Mozilla、Safari*/
var sel = window.getSelection();
if(sel.rangeCount > 0){
return sel.getRangeAt(0);
}
}else if(document.selection){
/*IE下的处理*/
return document.selection.createRange();
}
return null;
};
```
实例(可以试试在不同浏览器下的执行,点击里面的按钮btn2):Demo
**2、Range对象的属性和方法**
**2.1 创建Range对象(范围)**
`document.createRange()`:用于创建一个Range对象(范围)
**在IE下**:
`document.body.createTextRange()`:用于创建一个textRange对象
**2.2 Range对象的属性**
```
endContainer:返回范围的结束点的Document节点,通常是文本节点。
endOffset:返回endContainer中的结束点位置。
startContainer: 返回范围的开始点中的Document节点,通常是文本节点。
startOffset:返回startContainer中的开始点位置。
collapsed:用于判断范围的开始点与结束点是否处于相同的位置,如果相同,该属性值返回true,即范围是空的或折叠的。
commonAncestorContainer:范围的开始点和结束点的(即它们的祖先节点)、嵌套最深的 Document 节点。
```
注意:所有属性都是只读的。如果范围中存在空格,也会计算在偏移量内。
实例(点击里面的按钮btn3):Demo
**2.3 Range对象的方法**
**2.3.1 范围选择**
```
selectNode(node):设置该范围的边界点,使它包含指定节点和指定节点的所有子孙节点。
selectNodeContents(node):设置该范围的边界点,使它包含指定节点的子孙节点,但不包含指定节点本身。
```
**2.3.2 操作范围**
```
deleteContents():将Range对象中所包含的内容从页面中删除
setStart(node,index):将指定节点中的某处位置指定为Range对象所代表区域的起点位置
setEnd(node,index):将指定节点中的某处位置指定Range对象所代表区域的结束位置
setStartBefore(node):将指定节点的起点位置指定为Range对象所代表区域的起点位置。
setStartAfter():将指定节点的终点位置指定为Range对象所代表区域的起点位置。
setEndBefore():将指定节点的起点位置指定为Range对象所代表区域的终点位置。
setEndAfter(): 将指定节点的终点位置指定为Range对象所代表区域的终点位置。
cloneRange():对当前的Range对象进行复制,该方法返回一个复制的Range对象
cloneContents():复制当前Range对象所代表区域中的HTML代码并返回新的DocumentFragment对象。
extractContents():将Range对象所代表区域中的html代码克隆到一个DocumentFragment对象中,然后从页面中删除这段HTML代码
detach():释放Range对象。
insertNode(node):将指定的节点插入到某个Range对象所代表的区域中,插入位置为Range对象所代表区域的起点位置,如果该节点已经存在于页面中,该节点将被移动到Range对象代表的区域的起点处。
```
实例(关于setStart和setEnd,点击里面的按钮btn6):Demo
实例(关于deleteContents,点击里面的按钮btn7):Demo
实例(关于extractContents,点击里面的按钮btn8):Demo
**2.3.3 其他方法**
```
collpase(boolean) 用于使范围的边界点重合。当为true时,将范围的结束点设为与开始点相同的值;当为false时,将范围的开始点设为与结束点相同的值。
compareBoundaryPoints(how,sourceRange):用来比较两个Range对象,返回1,0,-1(0表示相等,等于1时,当前范围在sourceRange之后,等于-1时,当前范围在sourceRange之前)
toString():返回该范围表示的文档区域的纯文本内容。
```
**(1)compareBoundaryPoints()**
how的常量:
```
START_TO_START 用指定范围的开始点与当前范围的开始点进行比较。
START_TO_END 用指定范围的开始点与当前范围的结束点进行比较。
END_TO_END 用指定范围的结束点与当前范围的结束点进行比较。
END_TO_START 用指定范围的结束点与当前范围的开始点进行比较。
```
**4、selection对象**
selection对象可看作是Range对象的集合,包含一个或多个Range对象。
**4.1 属性**
```
anchorNode:返回范围的开始点的Document节点,和range对象的endContainer作用一样。
anchorOffset:返回startContainer中的开始点位置,和range对象的startOffset作用一样。
focusNode:返回范围的结束点的Document节点,和range对象的endContainer作用一样。
focusOffset:返回endContainer中的结束点位置,和range对象的endOffset作用一样。
isCollapsed:范围的开始点与结束点是否重叠
这是新标准中selection的属性,通过这些属性,我们省却了先获取range对象再获取偏移量和节点的繁琐。
```
实例(点击里面的按钮btn4):Demo
**4.2 方法**
```
removeAllRanges():删除selection中原有的所有range
addRange(range):将新的range添加到selection中
```
**5、HTMLInputElement的属性方法**
**5.1 在IE下Range对象**
**(1)属性
```
htmlText:返回字符串,为textRange的HTML内容,与innerHTML作用一样,只读
text:返回字符串,为textRange的文本内容,相当于innerText,可读写。
```
**(2)方法**
```
moveStart("character",index):选定范围的开始点向后移动index个字符
moveEnd("character",index):选定范围的结束点向后移动index个字符
pasterHTML():黏贴HTML到一个文本节点时,该文本节点自动分隔。
```
**5.2 在其他主流浏览器上**
**(1)属性**
```
selectionStart:获取范围的开始点,可读写
selectionEnd:获取范围的结束点,可读写
selectionDiraction
```
**(2) 方法**
```
select():在焦点状态下,移动光标至第一个字符后面
setSelectionRange(start,end):设置范围的开始点和结束点。
注意:selectionStart和selectionEnd会记录元素最后一次selection的相关属性,意思就是当元素失去焦点后,使用selectionStart和selectionEnd仍能够获取到元素失去焦点时的值。
setSelectionRange(start,end):
如果textbox没有selection时,selectionStart和selectionEnd相等,都是焦点的位置。
在使用setSelectionRange()时
如果end小于start,会讲selectionStart和selectionEnd都设置为end;
如果start和end参数大于textbox内容的长度(textbox.value.length),start和end都会设置为value属性的长度。
```
**3 操作富文本**
使用`document.execCommand()`方法是与富文本编辑器交互的重要方式,它可以对文档执行预定义的命令,而且可以应用大多数格式。
语法:
```
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
```
参数说明:
- aCommandName:String类型,命令名称
- aShowDefaultUI:Boolean类型,默认为false,是否展示用户界面,一般设为false。Mozilla没有实现。
- aValueArgument:String类型,一些命令需要额外的参数值(比如insertHTML需要提供HTML内容),默认为null,一般不需要参数时都使用null。
命令介绍:
```
backColor (用法:document.execCommand('backColor',bfalseb,Color); )
改变文档的背景颜色。 在styleWithCss模式,它影响的是包含元素的背景。 这个命令要求提供一个颜色值作为第三个参数 (Internet Explorer 使用这个命令设置文本背景色)
bold (用法: document.execCommand('Bold','false',null); )
对选中文本或者插入元素设置、取消粗体显示. (Internet Explorer 使用标签 而不是标签。)
contentReadOnly
转化文档进入只读或者可编辑模式. 这个命令要求提供给一个boolean值给第3个参数(ie不支持)。
copy 用法:document.execCommand('copy','false',null);
把当前选中区域复制到系统剪贴板。由于启用这个功能的条件因浏览器不同而不同,所以使用此功能时,请先检查浏览器是否支持。
createLink
当有选中区域的时候,将选中区域创建为一个锚点,需要提供一个URI给第3个参数. 这个URI必须至少包含一个字符,空白字符也可。(Internet Explorer会创建一个URI为空的a标签)
cut 用法:document.execCommand('cut','false',null);
剪切选中文本到剪切板. 同copy一样需要开启剪切板功能。
decreaseFontSize
给选中文本或者插入元素添加一个small标签。(Internet Explorer不支持)
delete 删除当前选中区域
enableInlineTableEditing
开启或禁用表的行和列的插入删除功能 ( Internet Explorer不支持)
enableObjectResizing
开启或禁用图片或者其他可调整元素大小的(resize)功能 ( Internet Explorer不支持)
fontName 用法:document.execCommand('fontName','false',sFontName);
改变选中文本或者插入元素的字体。需要给第3个参数提供一个字体值(例如:"Airal")
fontSize 用法:document.execCommand('fontSize','false',sSize|iSize);
改变选中文本或者插入元素的字体大小。需要给第3个参数提供一个数字
foreColor
改变选中文本或者插入元素的字体颜色。需要给第3个参数提供一个颜色值
formatBlock
添加一个HTML块式标签在包含当前选择的行,如果已经存在了,更换包含该行的块元素(在Firefox中的blockquote例外,它将包含任何包含块元素)。需要提供一个标签名称作为参数(比如:H1、P、DL、BLCOKQUOTE等)(IE仅支持标题标签H1-H6,ADDRESS和PRE,使用时还必须包含标签分隔符<>,比如
';