前面的話
一說起富文本,人們第一印象就是像使用word一樣,在網頁上操作文檔。實際上差不多就是這樣。富文本編輯,又稱為WYSIWYG (What You See Is What You Get所見即所得),指在網頁中編輯富文本內容。本文將詳細介紹如何通過javascript實現富文本編輯
方式
有兩種編輯富文本的方式,一種是使用iframe元素,另一種是使用contenteditable屬性
【1】iframe
在頁面中嵌入一個包含空HTML頁面的iframe。通過設置designMode屬性,這個空白的HTML頁面可以被編輯,而編輯對象則是該頁面<body>元素的HTML代碼
designMode屬性有兩個可能的值:"off"(默認值)和"on"。在設置為"on"時,整個文檔都會變得可以編輯
只有在頁面完全加載之后才能設置designMode屬性。因此,在包含頁面中,需要使用onload事件處理程序
[注意]此方法必須在服務器端才能執行,否則會提示跨域安全提示
<iframe name="wysiwyg" src="wysiwyg.html" style="height: 100px;width: 100px;"></iframe> <script> window.onload= function(){ frames['wysiwyg'].document.designMode = 'on'; } </script>
【2】contenteditable
把contenteditable屬性應用給頁面中的任何元素,然后用戶立即就可以編輯該元素
設置document.designMode='on'時,頁面的任意位置都可以編輯;使用contenteditable='true'則只對具體元素和其包含的元素起作用
[注意]一定要區分contenteditable和contentEditable。contenteditable是元素的特性,而contentEditable是對象的屬性
<div id="wysiwyg" style="height: 100px;width: 100px;border:1px solid black"></div> <button id="btn1">打開富文本編輯</button> <button id="btn2">關閉富文本編輯</button> <script> btn1.onclick = function(){wysiwyg.contentEditable = true;} btn2.onclick = function(){wysiwyg.contentEditable = false;} </script>
命令
與富文本編輯器交互的主要方式,就是使用document.execCommand()。這個方法可以對文檔執行預定義的命令,而且可以應用大多數格式
document.execCommand(String aCommandName, Boolean aShowDefaultUI, String aValueArgument)方法需要傳遞3個參數
aCommandName表示要執行的命令名稱,不可省略
aShowDefaultUI表示是否展示用戶界面,默認為false,可省略
aValueArgument表示額外參數值,默認為null,可省略
[注意]為了確保瀏覽器兼容性,第二個參數應始終設置為false,因為firefox在該參數為true時拋出錯誤
段落格式
居中 document.execCommand('justifyCenter');
左對齊 document.execCommand('justifyLeft');
右對齊 document.execCommand('justifyRight');
添加縮進 document.execCommand('indent');
去掉縮進 document.execCommand('outdent');
<div id="wysiwyg" style="height: 100px;width: 300px;border:1px solid black" contenteditable>測試內容</div> <button data-name="justifyCenter">居中</button> <button data-name="justifyLeft">左對齊</button> <button data-name="justifyRight">右對齊</button> <button data-name="indent">添加縮進</button> <button data-name="outdent">去掉縮進</button> <script> var btns = document.getElementsByTagName('button'); for(var i = 0; i < btns.length; i++){ btns[i].onclick = function(){ document.execCommand(this.getAttribute('data-name')); } } </script>
文本格式
字體類型 document.execCommand('fontname',false,sFontName)
字體大小 document.execCommand('fontsize',false,sFontSize)
字體顏色 document.execCommand('forecolor',false,sFontColor)
背景色 document.execCommand('backColor',false,sBackColor)
加粗 document.execCommand('bold');
斜體 document.execCommand('italic');
下劃線 document.execCommand('underline');
<div id="wysiwyg" style="height: 100px;width: 300px;border:1px solid black" contenteditable>測試內容</div> <button data-name="fontname" data-value="宋體">宋體</button> <button data-name="fontsize" data-value="5">大字體</button> <button data-name="forecolor" data-value="red">紅色字體</button> <button data-name="backColor" data-value="lightgreen">淺綠背景</button> <button data-name="bold">加粗</button> <button data-name="italic">斜體</button> <button data-name="underline">下劃線</button> <script> var btns = document.getElementsByTagName('button'); for(var i = 0; i < btns.length; i++){ btns[i].onclick = function(){ document.execCommand(this.getAttribute('data-name'),false,this.getAttribute('data-value')); } } </script>
編輯
復制 document.execCommand('copy');
剪切 document.execCommand('cut');
粘貼 document.execCommand('paste');(經測試無效)
全選 document.execCommand('selectAll');
刪除 document.execCommand('delete');
后刪除 document.execCommand('forwarddelete');
清空格式 document.execCommand('removeFormat');
前進一步 document.execCommand('redo');
后退一步 document.execCommand('undo');
打印 document.execCommand('print');(對firefox無效)
<div id="wysiwyg" style="height: 100px;width: 300px;border:1px solid black" contenteditable>測試內容</div> <button data-name="copy">復制</button> <button data-name="cut">剪切</button> <button data-name="paste">粘貼</button> <button data-name="selectAll">全選</button> <button data-name="delete">刪除</button> <button data-name="forwarddelete">后刪除</button> <button data-name="removeFormat">清空格式</button> <button data-name="redo">前進一步</button> <button data-name="undo">后退一步</button> <button data-name="print">打印</button> <script> var btns = document.getElementsByTagName('button'); for(var i = 0; i < btns.length; i++){ btns[i].onclick = function(){ document.execCommand(this.getAttribute('data-name')); } } </script>
插入
插入標簽 document.execCommand('formatblock',false,elementName); 插入<hr> document.execCommand('inserthorizontalrule'); 插入<ol> document.execCommand('insertorderedlist'); 插入<ul> document.execCommand('insertunorderedlist'); 插入<p> document.execCommand('insertparagraph'); 插入圖像 document.execCommand('insertimage',false,URL); 增加鏈接 document.execCommand('createlink',false,URL); 刪除鏈接 document.execCommand('unlink');
<div id="wysiwyg" style="height: 100px;width: 300px;border:1px solid black;overflow:auto" contenteditable>測試內容</div> <button data-name="formatblock" data-value="div">插入div</button> <button data-name="inserthorizontalrule">插入hr</button> <button data-name="insertorderedlist">插入ol</button> <button data-name="insertunorderedlist">插入ul</button> <button data-name="insertparagraph">插入p</button> <button data-name="insertimage" data-value="http://files.cnblogs.com/files/xiaohuochai/zan.gif">插入圖像</button> <button data-name="createlink" data-value="www.cnblogs.com/xiaohuochai">增加鏈接</button> <button data-name="unlink">刪除鏈接</button> <script> var btns = document.getElementsByTagName('button'); for(var i = 0; i < btns.length; i++){ btns[i].onclick = function(){ document.execCommand(this.getAttribute('data-name'),false,this.getAttribute('data-value')); } } </script>
選區
【getSelection()】
在富文本編輯器中,使用getSelection()方法,可以確定實際選擇的文本。這個方法是window對象和document對象的屬性,調用它會返回一個表示當前選擇文本的Selection對象。每個Selection對象都有下列屬性
[注意]IE8-瀏覽器不支持
anchorNode:選區起點所在的節點
anchorOffset:在到達選區起點位置之前跳過的anchorNode中的字符數量
focusNode:選區終點所在的節點
focusOffset:focusNode中包含在選區之內的字符數量
isCollapsed:布爾值,表示選區的起點和終點是否重合
rangeCount:選區中包含的DOM范圍的數量
Selection對象的這些屬性并沒有包含多少有用的信息。好在,該對象的下列方法提供了更多信息,并且支持對選區的操作
addRange(range):將指定的DOM范圍添加到選區中 collapse(node,offset):將選區折疊到指定節點中的相應的文本偏移位置 collapseToEnd():將選區折疊到終點位置 collapseToStart():將選區折疊到起點位置 containsNode(node):確定指定的節點是否包含在選區中 deleteFromDocument():從文檔中刪除選區中的文本,與document.execCommand("delete",false,null)命令的結果相同 extend(node,offset):通過將focusNode和focusOffset移動到指定的值來擴展選區 getRangeAt(index):返回索引對應的選區中的DOM范圍 removeAllRanges():從選區中移除所有DOM范圍。實際上,這樣會移除選區,因為選區中至少要有一個范圍 reomveRange(range):從選區中移除指定的DOM范圍 selectAllChildren(node):清除選區并選擇指定節點的所有子節點 toString():返回選區所包含的文本內容
Selection對象的這些方法都極為實用,它們利用了DOM范圍來管理選區。由于可以直接操作選擇文本的DOM表現,因此訪問DOM范圍與使用execCommand()相比,能夠對富文本編輯器進行更加細化的控制。下面來看一個例子
var selection = document.getSelection(); //取得選擇的文本 var selectionText = selection.toString(); //取得代表選區的范圍 var range = selection.getRangeAt(0); //突出顯示選擇的文本 var span = document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span);
以上代碼會為富文本編輯器中被選擇的文本添加黃色的背景。這里使用了默認選區中的DOM范圍,通過surroundContents()方法將選區添加到了帶有黃色背景的<span>元素中
HTML5將getSelection()方法納入了標準,IE8-瀏覽器不支持DOM范圍,但可以通過它支持的selection對象操作選擇的文本。IE中的selection對象是document的屬性,要取得富文本編輯器中選擇的文本,首先必須創建一個文本范圍,然后再像下面這樣訪問其text屬性
var range = document.selection.createRange(); var selectedText = range.text;
雖然使用IE的文本范圍來執行HTML操作并不像使用DOM范圍那么可靠,但也不失為一種有效的途徑。要像前面使用DOM范圍那樣實現相同的文本高亮效果,可以組合使用htmlText屬性和pasteHTML()方法
var range = document.selection.createRange(); range.pasteHTML("<span style=\"background-color:yellow\">" + range.htmlText+"</span>");
以上代碼通過htmlText取得了當前選區中的HTML,然后將其放在了一對<span>標簽中,最后又使用pasteHTML()將結果重新插入到了選區中
表單提交
因為富文本編輯不是使用表單控件實現的,因此富文本編輯器中的HTML不會被自動提交給服務器,而需要手工來提取并提交HTML。為此,通常可以添加一個隱藏的表單字段,讓它的值等于從iframe或使用contenteditable屬性的元素中提取出的HTML。具體來說,就是在提交表單之前提取出HTML,并將其插入到隱藏的字段中。下面就是通過表單的onsubmit事件處理程序實現上述操作的代碼
form.onsubmit = function(e){ e = e || event; var target = e.target || e.srcElement; target.elements["comments"].value = frames["richedit"].document.body.innerHTML; }
在此,通過文檔主體的innerHTML屬性取得了iframe中的HTML,然后將其插入到了名為"comments"的表單字段中。這樣可以確保恰好在提交表單之前填充"comments"字段。如果在代碼中通過submit()來手工提交表單,那么一定不要忘記事先執行上面的操作。對于contenteditable元素,也可以執行類似操作
form.onsubmit = function(e){ e = e || event; var target = e.target || e.srcElement; target.elements["comments"].value = document.getElementById('wysiwyg').innerHTML; }
最后
實現一個富文本編輯器,看似容易,但實際上是一個大工程
給大家推薦幾款不錯的在線富文本編輯器
歡迎交流
文章列表