文章出處

前面的話

  一說起富文本,人們第一印象就是像使用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;
}

 

最后

  實現一個富文本編輯器,看似容易,但實際上是一個大工程

   給大家推薦幾款不錯的在線富文本編輯器

  widgEditor

  wangeditor

  ueditor

  歡迎交流


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()