这部分我将详尽讲述如何插入复杂的html内容与取得编辑光标的位置,顺带完成插入表情的功能。由于IE与FF这两个闹别扭,这两步的实现都是完全不一样的。不说废话了!开始吧!

上次我们已经为我们的富文本编辑打造了表格创建器,但还没有绑定事件!我现在分析一下,当我们点击表格创建器的提交按扭,它应该会把其面板上输入的参数传到一个程序去处理,让它生成一个完整的表格的html,然后再插入到光标的所在位置,最后隐藏表格创建器;如果是点击取消按钮,则什么也不做就消失了!那个生成html的程序很简单,我们依然把它做成私有方法:

var _createTable = function(rows, cols, width){var builder = [];builder.push('<table border="1" width="');builder.push(width);builder.push('">');for(var r = 0; r < rows; r++){builder.push('<tr>');for(var c = 0; c < cols; c++){builder.push('<td> </td>');}builder.push('</tr>');}builder.push('</table>');return builder.join('');};

然后是插入html的方法,我们什么也不处理,看看到底是什么情况。


var _insertHTML = function(html){if(!+"\v1"){iframeDocument.selection.createRange().pasteHTML(html);       }else{_format('inserthtml',html);}
}

再然后是调用函数,我们把它绑定在onclick事件中!

$.addEvent(tableCreator, 'click', function(){var e = arguments[0] || window.event,current = e.srcElement ? e.srcElement : e.target,submit = $.ID('rte_submit'),cancel = $.ID('rte_cancel'),rows = $.ID('rows').value,cols = $.ID('cols').value,width = $.ID('width').value;if(current==cancel) {this.style.display = 'none';return;}else if(current==submit){var html = _createTable(rows, cols, width);_insertHTML(html);this.style.display = "none";}});

<!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"> #textarea {width:600px;height:300px;background:#F2F1D7;} </style> <script type="text/javascript"> var addSheet = function(){ var doc,cssCode; if(arguments.length == 1){ doc = document; cssCode = arguments[0]; }else if(arguments.length == 2){ doc = arguments[0]; cssCode = arguments[1]; }else{ alert("addSheet函数最多接受两个参数!"); } var headElement = doc.getElementsByTagName("head")[0]; var styleElements = headElement.getElementsByTagName("style"); if(styleElements.length == 0){/*如果不存在style元素则创建*/ if(!+"\v1"){ //ie doc.createStyleSheet(); }else{ var tempStyleElement = doc.createElement('style');//w3c tempStyleElement.setAttribute("type", "text/css"); headElement.appendChild(tempStyleElement); } } var styleElement = styleElements[0]; var media = styleElement.getAttribute("media"); if(media != null && !/screen/.test(media.toLowerCase()) ){ styleElement.setAttribute("media","screen"); } if(!+"\v1"){ //ie styleElement.styleSheet.cssText += cssCode; }else if(/a/[-1]=='a'){ styleElement.innerHTML += cssCode;//火狐支持直接innerHTML添加样式表字串 }else{ styleElement.appendChild(doc.createTextNode(cssCode)) } } var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } var RichTextEditor = Class.create();//我们的富文本编辑器类 RichTextEditor.prototype = { initialize:function(options){ this.setOptions(options); this.drawEditor(this.options.textarea_id); }, setOptions:function(options){ this.options = { //这里集中设置默认属性 id:'jeditor_'+ new Date().getTime(), textarea_id:null//用于textarea的ID,也就是我们的必选项 } extend(this.options, options || {});//这里是用来重写默认属性 }, ID:function(id){return document.getElementById(id) },//getElementById的快捷方式 TN:function(tn){ return document.getElementsByTagName(tn) },//getElementsByTagName的快捷方式 CE:function(s){ return document.createElement(s)},//createElement的快捷方式 fontPickerHtml:function(type,array){ var builder = []; for(var i = 0,l = array.length;i<l;i++){ builder.push('<a unselectable="on" style="'); if(type == 'fontname'){ builder.push('font-family'); builder.push(':'); builder.push(array[i]); /*呈现一行(一行就是一种字体)*/ builder.push(';" href="javascript:void(0)">'); builder.push(array[i]); }else if(type == 'fontsize'){ /*呈现一行(一行就是一种字号)*/ builder.push('font-size'); builder.push(':'); builder.push(array[i][1]); builder.push(';" sizevalue="'); builder.push(array[i][0]); builder.push('" href="javascript:void(0)">'); builder.push(array[i][2]); } builder.push("</a>"); } return builder.join(''); }, tableHtml: function(){ var _drawInput = function(builder, name, value){ builder.push('<input id="'); builder.push(name); builder.push('" value="');builder.push(value);builder.push('" />'); }; var builder = []; builder.push('<table>'); // 标题 builder.push('<tr><td colspan="2" style="padding:2px" bgcolor="#D0E8FC">'); builder.push('插入表格'); builder.push('</td></tr>'); // 行数 builder.push('<tr><td>行数</td><td>'); _drawInput(builder, 'rows', 3); builder.push('</td></tr>'); // 列数 builder.push('<tr><td>列数</td><td>'); _drawInput(builder, 'cols', 5); builder.push('</td></tr>'); // 宽度 builder.push('<tr><td>宽度</td><td>'); _drawInput(builder, 'width', 300); builder.push('</td></tr>'); // 提交 builder.push('<tr><td colspan="2" style="padding-top:6px;">'); builder.push('<input type="button" id="rte_submit" value="提交" unselectable="on" />'); builder.push('<input type="button" id="rte_cancel" value="取消" unselectable="on" />'); builder.push('</td></tr>'); builder.push('</table>'); return builder.join(''); }, //用于生成颜色选择器的具体内容 colorPickerHtml : function(){ var _hex = ['FF', 'CC', '99', '66', '33', '00']; var builder = []; // 呈现一个颜色格 var _drawCell = function(builder, red, green, blue){ builder.push('<td bgcolor="'); builder.push('#' + red + green + blue); builder.push('" unselectable="on"></td>'); }; // 呈现一行颜色 var _drawRow = function(builder, red, blue){ builder.push('<tr>'); for (var i = 0; i < 6; ++i) { _drawCell(builder, red, _hex[i], blue) } builder.push('</tr>'); }; // 呈现六个颜色区之一 var _drawTable = function(builder, blue){ builder.push('<table class="cell" unselectable="on">'); for (var i = 0; i < 6; ++i) { _drawRow(builder, _hex[i], blue) } builder.push('</table>'); }; //开始创建 builder.push('<table><tr>'); for (var i = 0; i < 3; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]); builder.push('</td>'); } builder.push('</tr><tr>'); for (var i = 3; i < 6; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]) builder.push('</td>'); } builder.push('</tr></table>'); builder.push('<table id="color_result"><tr><td id="color_view"></td><td id="color_code"></td></tr></table>'); return builder.join(''); }, addEvent:function(el, type, fn ) { if(!+"\v1") { el['e'+type+fn]=fn; el.attachEvent( 'on'+type, function() { el['e'+type+fn](); } ); }else{ el.addEventListener( type, fn, false ); } }, drawEditor:function(id){ var $ = this, textarea = this.ID(id), toolbar = this.CE('div'), br = this.CE('br'),//用于清除浮动 iframe = this.CE('iframe'); textarea.style.display = "none"; textarea.parentNode.insertBefore(toolbar,textarea); textarea.parentNode.insertBefore(br,textarea); textarea.parentNode.insertBefore(iframe,textarea); br.style.cssText = "clear:both"; toolbar.setAttribute("id","RTE_toolbar"); iframe.setAttribute("id","RTE_iframe"); iframe.frameBorder=0; var iframeDocument = iframe.contentDocument || iframe.contentWindow.document; iframeDocument.designMode = "on"; iframeDocument.open(); iframeDocument.write('<html><head><style type="text/css">body{ font-family:arial; font-size:13px;background:#DDF3FF;border:0; }</style></head></html>'); iframeDocument.close(); var buttons = {//工具栏的按钮集合 'removeFormat':'还原', 'bold': '加粗', 'italic': '斜体', 'underline': '下划线', 'strikethrough':'删除线', 'justifyleft': '居左', 'justifycenter': '居中', 'justifyright': '居右', 'indent':'缩进', 'outdent':'悬挂', 'forecolor':'前景色', 'backcolor':'背景色', 'createlink': '超链接', 'insertimage': '插图', 'fontname': '字体', 'fontsize': '字码', 'insertorderedlist':'有序列表', 'insertunorderedlist':'无序列表', 'table':'插入表格', 'html':'查看' }; var fontFamilies = ['宋体','经典中圆简','微软雅黑', '黑体', '楷体', '隶书', '幼圆', 'Arial', 'Arial Narrow', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Georgia', 'New Roman Times', 'Verdana'] var fontSizes= [[1, 'xx-small', '最小'], [2, 'x-small', '特小'], [3, 'small', '小'], [4, 'medium', '中'], [5, 'large', '大'], [6, 'x-large', '特大'], [7, 'xx-large', '最大']]; var buttonClone = $.CE("a"), fragment = document.createDocumentFragment(); buttonClone.className = 'button'; for (var i in buttons){/*添加命令按钮的名字,样式*/ var button = buttonClone.cloneNode("true"); if(i == 'backcolor'){/*特殊处理背景色按钮*/ if (!+"\v1"){ button.setAttribute("title","background") }else{ button.setAttribute("title","hilitecolor") } } button.setAttribute("title",i);/*把execCommand的命令参数放到title*/ button.innerHTML = buttons[i]; button.setAttribute("unselectable", "on");/*防止焦点转移到点击的元素上,从而保证文本的选中状态*/ toolbar[i] = button; /*★★★★把元素放进一个数组,用于下一个循环绑定事件!★★★★*/ fragment.appendChild(button); } toolbar.appendChild(fragment); $.addEvent(toolbar, 'click', function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = target.getAttribute("title"); switch (command){ case 'createlink': case 'insertimage': var value = prompt('请输入网址:', 'http://'); _format(command,value); break; case 'fontname'://这六个特殊处理,不直接执行fontEdit命令! case 'fontsize': case 'forecolor': case 'backcolor': case 'html': case 'table': return; default://其他执行fontEdit(cmd, null)命令 _format(command,''); break; } }); /*******************************************************/ var fontPicker = $.CE('div'); fontPicker.className = "fontpicker"; toolbar.appendChild(fontPicker); /*******************************************************/ $.addEvent(toolbar['fontname'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontname',fontFamilies); fontPicker.style.width = "150px"; bind_select_event(this,fontPicker); }); /*******************************************************/ $.addEvent(toolbar['fontsize'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontsize',fontSizes); fontPicker.style.width = "100px"; bind_select_event(this,fontPicker); }); /*******************************************************/ var bind_select_event = function(button,picker){//显示或隐藏选择器 button.style.position = 'relative'; var command = button.getAttribute("title"); if('backcolor' == command){ command = !+"\v1" ? 'backcolor':'hilitecolor'; } picker.setAttribute("title",command);//转移命令 if(picker.style.display == 'none'){ picker.style.display = 'block'; picker.style.left = button.offsetLeft + 'px'; picker.style.top = (button.clientHeight + button.offsetTop)+ 'px'; }else{ picker.style.display='none'; } } /*******************************************************/ $.addEvent(fontPicker,'click',function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = this.getAttribute("title"); var nn = target.nodeName.toLowerCase(); if(nn == 'a'){ var value; if('fontsize' == command){ value = target.getAttribute('sizevalue'); }else{ value = target.innerHTML; } _format(command,value); e.cancelBubble = true; fontPicker.style.display = 'none'; } }); /*******************************************************/ var colorPicker = $.CE('div'); toolbar.appendChild(colorPicker); colorPicker.className = "colorpicker"; colorPicker.innerHTML = $.colorPickerHtml(); /*******************************************************/ $.addEvent(toolbar['forecolor'],'click',function(){ bind_select_event(this,colorPicker); }); $.addEvent(toolbar['backcolor'],'click',function(){ bind_select_event(this,colorPicker); }); /*******************************************************/ $.addEvent(colorPicker,'mouseover',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(), colorView = $.ID('color_view'), colorCode = $.ID('color_code'); if( 'td' == nn){ colorView.style.backgroundColor = td.bgColor; colorCode.innerHTML = td.bgColor; } }); /*******************************************************/ $.addEvent(colorPicker,'click',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(); if(nn == 'td'){ var command = colorPicker.getAttribute("title"), value = td.bgColor; _format(command,value); e.cancelBubble = true; colorPicker.style.display = 'none'; } }); var _format = function(x,y){//核心代码1,用于格式化 try{ iframeDocument.execCommand(x,false,y); iframe.contentWindow.focus(); }catch(e){} } /********切换回代码界面*************/ var _doHTML = function() { iframe.style.display = "none"; textarea.style.display = "block"; textarea.value = iframeDocument.body.innerHTML; textarea.focus(); }; /********切换回富文本编辑器界面*************/ var _doRich = function() { iframe.style.display = "block"; textarea.style.display = "none"; iframeDocument.body.innerHTML = textarea.value; iframe.contentWindow.focus(); }; /********切换编辑模式的开关*************/ var switchEditMode = true; $.addEvent(toolbar['html'], 'click', function(){ if(switchEditMode){ _doHTML(); switchEditMode = false; }else{ _doRich(); switchEditMode = true; } }); /***********************************************************/ $.addEvent(iframe.contentWindow,"blur",function(){ textarea.value = iframeDocument.body.innerHTML; }); /*************************************************/ var tableCreator = $.CE('div'); tableCreator.className = 'tablecreator'; toolbar.appendChild(tableCreator); tableCreator.innerHTML = $.tableHtml(); $.addEvent(toolbar['table'],'click',function(){ bind_select_event(this,tableCreator); }); /************************************************/ $.addEvent(tableCreator, 'click', function(){ var e = arguments[0] || window.event, current = e.srcElement ? e.srcElement : e.target, submit = $.ID('rte_submit'), cancel = $.ID('rte_cancel'), rows = $.ID('rows').value, cols = $.ID('cols').value, width = $.ID('width').value; if(current==cancel) { this.style.display = 'none'; return; }else if(current==submit){ var html = _createTable(rows, cols, width); _insertHTML(html); this.style.display = "none"; } }); var _createTable = function(rows, cols, width){ var builder = []; builder.push('<table border="1" width="'); builder.push(width); builder.push('">'); for(var r = 0; r < rows; r++){ builder.push('<tr>'); for(var c = 0; c < cols; c++){ builder.push('<td> </td>'); } builder.push('</tr>'); } builder.push('</table>'); return builder.join(''); }; var _insertHTML = function(html){ _format('inserthtml',html); } /*********************************************************/ addSheet('\ #RTE_iframe{width:600px;height:300px;}\ #RTE_toolbar{float:left;width:600px;background:#D5F3F4;}\ #RTE_toolbar .button{display:block;float:left;border:1px solid #CCC;margin-left:5px;\ color:#000;background:#D0E8FC;height:20px;text-align:center;padding:0 10px;white-space: nowrap;}\ #RTE_toolbar select{float:left;height:20px;width:60px;margin-right:5px;}\ #RTE_toolbar .button:hover{color:#fff;border-color:#fff #aaa #aaa #fff;}\ div.fontpicker{display:none;height:150px;overflow:auto;position:absolute;\ border:2px solid #c3c9cf;background:#F1FAFA;}\ div.fontpicker a{display:block;text-decoration:none;color:#000;background:#F1FAFA;padding:2px;}\ div.fontpicker a:hover{color:#999;background:#e3e6e9;}\ div.colorpicker {display:none;position:absolute;width:216px;border:2px solid #c3c9cf;background:#f8f8f8;}\ div.colorpicker table{border-collapse:collapse;margin:0;padding:0;}\ div.colorpicker .cell td{height:12px;width:12px;}\ #color_result{width:216px;}\ #color_view{width:110px;height:25px;}\ div.tablecreator{display:none;width:176px;position:absolute;border:2px solid #c3c9cf;background:#f8f8f8;padding:1px;}\ div.tablecreator table{border:1px solid #69f;line-height:12px;font-size:12px;border-collapse:collapse;width:100%;}\ div.tablecreator td{font-size:12px;color:#777;text-align:center;}\ #rte_submit,#rte_cancel{font-size:12px;color:#777;border:1px solid #777;background-color:#f4f4f4;margin:5px 3px;}\ #rows, #cols, #width{width:80px;height:14px;line-height:12px;font-size:12px;border:1px solid #69f;}'); } } window.onload = function(){ new RichTextEditor({ id:'editor', textarea_id:'textarea' }); } </script> <title>富文本编辑器</title> </head> <body> <form action="#"> <textarea id="textarea" wrap="on"></textarea> </form> </body> </html>

运行代码

发现IE8依然没有反应,FF的最新版本运行良好。下面是分别给出解决的方法。

IE中是利用bookmark对象。这是一个不透明的对象,我们不可以利用toString()方法取得它的内容。它类似google的“网页快照”,能保存我们选中的文本片段。我们可以利用TextRangeName.getbookmark()生成一个bookmark对象,当我们选中文本时,它会自动存入bookmark中。下面是老外给出的有关bookmark的示范。

<!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"> </style> <title>IE的bookmark对象</title> </head> <body> <h1>Using getBookmark and moveToBookmark</h1> </div> <p>The getBookmark method doesn't do what you might initially think. It doesn't allow you to create a link to an internet shortcut or get one from the user's machine. What it does do is create a "snapshot" of a selection so you can return to it later. The information returned from the getBookmark method is opaque. This means that it is unreadable and doesn't have any context on it's own. It can only be used by the moveToBookmark method to move to the saved selection.</p> <p><strong>Example:</strong></p> <script type="text/javascript" language="JavaScript"> <!--// var bk1, bk2; function get1(){if(document.selection.type=="Text"){bk1 = document.selection.createRange().getBookmark();}} function get2(){if(document.selection.type=="Text"){bk2 = document.selection.createRange().getBookmark();}} function move1(){var r = document.body.createTextRange();r.moveToBookmark(bk1);r.select();} function move2(){var r = document.body.createTextRange();r.moveToBookmark(bk2);r.select();} //--> </script> <p>Select any text on this page and then click here: <input name="btnTest" type="button" id="btnTest" style="width: 75px; height:20px; border:2px outset #CECECE;" value="Get First" οnclick="get1()" /> . This has created a bookmark that has been saved to a variable. Now, select another block of text on the page and then click here: <input name="btnTest2" type="button" id="btnTest2" style="width: 75px; height:20px; border:2px outset #CECECE;" value="Get Second" οnclick="get2()" /> . You now have two bookmarks stored in variables that can be retreived at any time.</p> <p> <input name="btnMove" type="button" id="btnMove" style="width: 75px; height:20px; border:2px outset #CECECE;" value="Move to 1st" οnclick="move1()" /> <input name="btnMove2" type="button" id="btnMove2" style="width: 75px; height:20px; border:2px outset #CECECE;" value="Move to 2nd" οnclick="move2()" /> </p> <p>An example application of this feature could be a content highlighter for your companies intranet. It would allow your employees to browse articles and highlight information that they found interesting. The bookmarks to this highlighted information could be stored in a database. The next time the user browsed to the page you would use moveToBookmark to "relight" that information.</p> <h3>Problems with getBookmark</h3> <p>The biggest problem with using getBookmark is any change that is made to the HTML on the page may cause unusual behaviour. Any content within a sentence of the content that has been changed will likely cause the moveToBookmark method to either select the incorrect text or not work at all. This is especially troublesome when using these methods with the MSHTML or DEC as the likelihood of the content having changed since you bookmarked it is quite likely.</p> </body> </html>

运行代码

接下来就简单了,当文档即将失去焦点时,我们把选项中的文本存在入bookmark对象,当文档再次获得焦点时,我们恢复选中的文本,并在它的后面插入你要插入的内容。

if(!+"\v1"){var bookmark;//记录IE的编辑光标$.addEvent(iframe,"beforedeactivate",function(){//在文档失去焦点之前var range = iframeDocument.selection.createRange();bookmark= range.getBookmark();});//恢复IE的编辑光标$.addEvent(iframe,"activate",function(){if(bookmark){var range = iframeDocument.body.createTextRange();range.moveToBookmark(bookmark);range.select();bookmark = null;}});}

有关beforedeactivate与activate的用法,可以参考这里与这里

有人可能会问,为什么不用onblur呢?!它们都是在元素失去焦点时激发!那是因为onbeforedeactive有一个很重要的激活条件——"Fires immediately before the active element is changed from the current object to another object in the parent document."而我们的要求也是当我们的鼠标转移到外面的文档时记录光标位置才有意义!

当焦点离开文档,并不会改变活动元素,也不会派往发onbeforedeactivate事件。我们可以用setAtive()或focus()方法让一个元素成为活动元素,每一个文档最多只有一个活动元素。setActive()不会让文档产生焦点,focus()方法则相反,并让此元素成为活动元素。一个活动元素在失去焦点时会依次发生如下事件:onbeforedeactivate,ondeactivate,和 onblur。 http://snook.ca/archives/mshtml_and_dec/using_getbookma/ http://topic.csdn.net/u/20080222/12/4a8b7832-2298-4ab6-9dc2-779b00ebcce6.html

至于FF,我们可以利用selection对象,它和TextRange对象一样,当我们选中文本时,它会自动存入对象中。我们可以用window.getSelection().getRangeAt(0)或window.getSelection().toString()查看到这些选中的内容。然后插入就不是利用execCommand的inserthtml命令了,而是直接利用Range对象编辑selection的文本就是!

我们首先需要把要插入的内容转化为DocumentFragment。我们可以利用range.createContextualFragment(html) 方法,然后利用insertNode方法把DocumentFragment 加入到range中去,然后再用addRange方法,把range添加到selection中去。


var selection = iframe.contentWindow.getSelection();//取得selection(我们刚才选中的文本)
var range;if (selection) {//如果selection不为空,就在selection中创建range对象range = selection.getRangeAt(0);}else {range = iframeDocument.createRange();//否则在iframe的document创建一个}var oFragment = range.createContextualFragment(html),//把插入内容转变为DocumentFragmentoLastNode = oFragment.lastChild ;//用于修正编辑光标的位置range.insertNode(oFragment) ;range.setEndAfter(oLastNode ) ;//把编辑光标放到我们插入内容之后range.setStartAfter(oLastNode );selection.removeAllRanges();//清除所有选择,要不我们插入的内容与刚才的文本处于选中状态selection.addRange(range);//插入内容

<!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"> #textarea {width:600px;height:300px;background:#F2F1D7;} </style> <script type="text/javascript"> var addSheet = function(){ var doc,cssCode; if(arguments.length == 1){ doc = document; cssCode = arguments[0]; }else if(arguments.length == 2){ doc = arguments[0]; cssCode = arguments[1]; }else{ alert("addSheet函数最多接受两个参数!"); } var headElement = doc.getElementsByTagName("head")[0]; var styleElements = headElement.getElementsByTagName("style"); if(styleElements.length == 0){/*如果不存在style元素则创建*/ if(!+"\v1"){ //ie doc.createStyleSheet(); }else{ var tempStyleElement = doc.createElement('style');//w3c tempStyleElement.setAttribute("type", "text/css"); headElement.appendChild(tempStyleElement); } } var styleElement = styleElements[0]; var media = styleElement.getAttribute("media"); if(media != null && !/screen/.test(media.toLowerCase()) ){ styleElement.setAttribute("media","screen"); } if(!+"\v1"){ //ie styleElement.styleSheet.cssText += cssCode; }else if(/a/[-1]=='a'){ styleElement.innerHTML += cssCode;//火狐支持直接innerHTML添加样式表字串 }else{ styleElement.appendChild(doc.createTextNode(cssCode)) } } var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } var RichTextEditor = Class.create();//我们的富文本编辑器类 RichTextEditor.prototype = { initialize:function(options){ this.setOptions(options); this.drawEditor(this.options.textarea_id); }, setOptions:function(options){ this.options = { //这里集中设置默认属性 id:'jeditor_'+ new Date().getTime(), textarea_id:null//用于textarea的ID,也就是我们的必选项 } extend(this.options, options || {});//这里是用来重写默认属性 }, ID:function(id){return document.getElementById(id) },//getElementById的快捷方式 TN:function(tn){ return document.getElementsByTagName(tn) },//getElementsByTagName的快捷方式 CE:function(s){ return document.createElement(s)},//createElement的快捷方式 fontPickerHtml:function(type,array){ var builder = []; for(var i = 0,l = array.length;i<l;i++){ builder.push('<a unselectable="on" style="'); if(type == 'fontname'){ builder.push('font-family'); builder.push(':'); builder.push(array[i]); /*呈现一行(一行就是一种字体)*/ builder.push(';" href="javascript:void(0)">'); builder.push(array[i]); }else if(type == 'fontsize'){ /*呈现一行(一行就是一种字号)*/ builder.push('font-size'); builder.push(':'); builder.push(array[i][1]); builder.push(';" sizevalue="'); builder.push(array[i][0]); builder.push('" href="javascript:void(0)">'); builder.push(array[i][2]); } builder.push("</a>"); } return builder.join(''); }, tableHtml: function(){ var _drawInput = function(builder, name, value){ builder.push('<input id="'); builder.push(name); builder.push('" value="'); builder.push(value); builder.push('" />'); }; var builder = []; builder.push('<table>'); // 标题 builder.push('<tr><td colspan="2" style="padding:2px" bgcolor="#D0E8FC">'); builder.push('插入表格'); builder.push('</td></tr>'); // 行数 builder.push('<tr><td>行数</td><td>'); _drawInput(builder, 'rows', 3); builder.push('</td></tr>'); // 列数 builder.push('<tr><td>列数</td><td>'); _drawInput(builder, 'cols', 5); builder.push('</td></tr>'); // 宽度 builder.push('<tr><td>宽度</td><td>'); _drawInput(builder, 'width', 300); builder.push('</td></tr>'); // 提交 builder.push('<tr><td colspan="2" style="padding-top:6px;">'); builder.push('<input type="button" id="rte_submit" value="提交" unselectable="on" />'); builder.push('<input type="button" id="rte_cancel" value="取消" unselectable="on" />'); builder.push('</td></tr>'); builder.push('</table>'); return builder.join(''); }, //用于生成颜色选择器的具体内容 colorPickerHtml : function(){ var _hex = ['FF', 'CC', '99', '66', '33', '00']; var builder = []; // 呈现一个颜色格 var _drawCell = function(builder, red, green, blue){ builder.push('<td bgcolor="'); builder.push('#' + red + green + blue); builder.push('" unselectable="on"></td>'); }; // 呈现一行颜色 var _drawRow = function(builder, red, blue){ builder.push('<tr>'); for (var i = 0; i < 6; ++i) { _drawCell(builder, red, _hex[i], blue) } builder.push('</tr>'); }; // 呈现六个颜色区之一 var _drawTable = function(builder, blue){ builder.push('<table class="cell" unselectable="on">'); for (var i = 0; i < 6; ++i) { _drawRow(builder, _hex[i], blue) } builder.push('</table>'); }; //开始创建 builder.push('<table><tr>'); for (var i = 0; i < 3; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]); builder.push('</td>'); } builder.push('</tr><tr>'); for (var i = 3; i < 6; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]) builder.push('</td>'); } builder.push('</tr></table>'); builder.push('<table id="color_result"><tr><td id="color_view"></td><td id="color_code"></td></tr></table>'); return builder.join(''); }, addEvent:function(el, type, fn ) { if(!+"\v1") { el['e'+type+fn]=fn; el.attachEvent( 'on'+type, function() { el['e'+type+fn](); } ); }else{ el.addEventListener( type, fn, false ); } }, drawEditor:function(id){ var $ = this, textarea = this.ID(id), toolbar = this.CE('div'), br = this.CE('br'),//用于清除浮动 iframe = this.CE('iframe'); textarea.style.display = "none"; textarea.parentNode.insertBefore(toolbar,textarea); textarea.parentNode.insertBefore(br,textarea); textarea.parentNode.insertBefore(iframe,textarea); br.style.cssText = "clear:both"; toolbar.setAttribute("id","RTE_toolbar"); iframe.setAttribute("id","RTE_iframe"); iframe.frameBorder=0; var iframeDocument = iframe.contentDocument || iframe.contentWindow.document; iframeDocument.designMode = "on"; iframeDocument.open(); iframeDocument.write('<html><head><style type="text/css">body{ font-family:arial; font-size:13px;background:#DDF3FF;border:0; }</style></head></html>'); iframeDocument.close(); var buttons = {//工具栏的按钮集合 'removeFormat':'还原', 'bold': '加粗', 'italic': '斜体', 'underline': '下划线', 'strikethrough':'删除线', 'justifyleft': '居左', 'justifycenter': '居中', 'justifyright': '居右', 'indent':'缩进', 'outdent':'悬挂', 'forecolor':'前景色', 'backcolor':'背景色', 'createlink': '超链接', 'insertimage': '插图', 'fontname': '字体', 'fontsize': '字码', 'insertorderedlist':'有序列表', 'insertunorderedlist':'无序列表', 'table':'插入表格', 'html':'查看' }; var fontFamilies = ['宋体','经典中圆简','微软雅黑', '黑体', '楷体', '隶书', '幼圆', 'Arial', 'Arial Narrow', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Georgia', 'New Roman Times', 'Verdana'] var fontSizes= [[1, 'xx-small', '最小'], [2, 'x-small', '特小'], [3, 'small', '小'], [4, 'medium', '中'], [5, 'large', '大'], [6, 'x-large', '特大'], [7, 'xx-large', '最大']]; var buttonClone = $.CE("a"), fragment = document.createDocumentFragment(); buttonClone.className = 'button'; for (var i in buttons){/*添加命令按钮的名字,样式*/ var button = buttonClone.cloneNode("true"); if(i == 'backcolor'){/*特殊处理背景色按钮*/ if (!+"\v1"){ button.setAttribute("title","background") }else{ button.setAttribute("title","hilitecolor") } } button.setAttribute("title",i);/*把execCommand的命令参数放到title*/ button.innerHTML = buttons[i]; button.setAttribute("unselectable", "on");/*防止焦点转移到点击的元素上,从而保证文本的选中状态*/ toolbar[i] = button; /*★★★★把元素放进一个数组,用于下一个循环绑定事件!★★★★*/ fragment.appendChild(button); } toolbar.appendChild(fragment); $.addEvent(toolbar, 'click', function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = target.getAttribute("title"); switch (command){ case 'createlink': case 'insertimage': var value = prompt('请输入网址:', 'http://'); _format(command,value); break; case 'fontname'://这六个特殊处理,不直接执行fontEdit命令! case 'fontsize': case 'forecolor': case 'backcolor': case 'html': case 'table': return; default://其他执行fontEdit(cmd, null)命令 _format(command,''); break; } }); /******************************************************************/ var fontPicker = $.CE('div'); fontPicker.className = "fontpicker"; toolbar.appendChild(fontPicker); /******************************************************************/ $.addEvent(toolbar['fontname'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontname',fontFamilies); fontPicker.style.width = "150px"; bind_select_event(this,fontPicker); }); /******************************************************************/ $.addEvent(toolbar['fontsize'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontsize',fontSizes); fontPicker.style.width = "100px"; bind_select_event(this,fontPicker); }); /******************************************************************/ $.addEvent(fontPicker,'click',function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = this.getAttribute("title"); var nn = target.nodeName.toLowerCase(); if(nn == 'a'){ var value; if('fontsize' == command){ value = target.getAttribute('sizevalue'); }else{ value = target.innerHTML; } _format(command,value); e.cancelBubble = true; fontPicker.style.display = 'none'; } }); /******************************************************************/ var colorPicker = $.CE('div'); toolbar.appendChild(colorPicker); colorPicker.className = "colorpicker"; colorPicker.innerHTML = $.colorPickerHtml(); /******************************************************************/ $.addEvent(toolbar['forecolor'],'click',function(){ bind_select_event(this,colorPicker); }); $.addEvent(toolbar['backcolor'],'click',function(){ bind_select_event(this,colorPicker); }); /******************************************************************/ $.addEvent(colorPicker,'mouseover',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(), colorView = $.ID('color_view'), colorCode = $.ID('color_code'); if( 'td' == nn){ colorView.style.backgroundColor = td.bgColor; colorCode.innerHTML = td.bgColor; } }); /******************************************************************/ $.addEvent(colorPicker,'click',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(); if(nn == 'td'){ var cmd = colorPicker.getAttribute("title"); var val = td.bgColor; _format(cmd,val); e.cancelBubble = true; colorPicker.style.display = 'none'; } }); /********切换回代码界面********************************************/ var _doHTML = function() { iframe.style.display = "none"; textarea.style.display = "block"; textarea.value = iframeDocument.body.innerHTML; textarea.focus(); }; /********切换回富文本编辑器界面*************************************/ var _doRich = function() { iframe.style.display = "block"; textarea.style.display = "none"; iframeDocument.body.innerHTML = textarea.value; iframe.contentWindow.focus(); }; /********切换编辑模式的开关*******************************************/ var switchEditMode = true; $.addEvent(toolbar['html'], 'click', function(){ if(switchEditMode){ _doHTML(); switchEditMode = false; }else{ _doRich(); switchEditMode = true; } }); /******************************************************************/ var tableCreator = $.CE('div'); toolbar.appendChild(tableCreator); tableCreator.innerHTML = $.tableHtml(); tableCreator.className = 'tablecreator'; $.addEvent(toolbar['table'],'click',function(){ bind_select_event(this,tableCreator); }); $.addEvent(tableCreator, 'click', function(){ var e = arguments[0] || window.event, current = e.srcElement ? e.srcElement : e.target, submit = $.ID('rte_submit'), cancel = $.ID('rte_cancel'), rows = $.ID('rows').value, cols = $.ID('cols').value, width = $.ID('width').value; if(current==cancel) { this.style.display = 'none'; return; }else if(current==submit){ var html = _createTable(rows, cols, width); _insertHTML(html); this.style.display = "none"; } }); var _createTable = function(rows, cols, width){ var builder = []; builder.push('<table border="1" width="'); builder.push(width); builder.push('">'); for(var r = 0; r < rows; r++){ builder.push('<tr>'); for(var c = 0; c < cols; c++){ builder.push('<td> </td>'); } builder.push('</tr>'); } builder.push('</table>'); return builder.join(''); }; var _insertHTML = function(html){ iframe.contentWindow.focus(); if(!+"\v1"){ /****这里需要解决IE丢失光标位置的问题,详见核心代码四**************/ iframeDocument.selection.createRange().pasteHTML(html); }else{ var selection = iframe.contentWindow.getSelection(); var range; if (selection) { range = selection.getRangeAt(0); }else { range = iframeDocument.createRange(); } var oFragment = range.createContextualFragment(html), oLastNode = oFragment.lastChild ; range.insertNode(oFragment) ; range.setEndAfter(oLastNode ) ; range.setStartAfter(oLastNode ); selection.removeAllRanges();//清除选择 selection.addRange(range); } } /*******************核心代码之一******************************************/ /********************处理富文本编辑器的格式化命令**************************/ var _format = function(x,y){ try{ iframeDocument.execCommand(x,false,y); iframe.contentWindow.focus(); }catch(e){} } /***********核心代码之二*************************************************/ /***********隐藏与显示弹出层**********************************************/ var bind_select_event = function(button,picker){ button.style.position = 'relative'; var command = button.getAttribute("title"); if('backcolor' == command){ command = !+"\v1" ? 'backcolor':'hilitecolor'; } picker.setAttribute("title",command);//转移命令 if(picker.style.display == 'none'){ picker.style.display = 'block'; picker.style.left = button.offsetLeft + 'px'; picker.style.top = (button.clientHeight + button.offsetTop)+ 'px'; }else{ picker.style.display='none'; } } /*******************核心代码之三******************************************/ /**********************获取iframe的内容************************************/ $.addEvent(iframe.contentWindow,"blur",function(){ textarea.value = iframeDocument.body.innerHTML; }); /*******************核心代码之四******************************************/ /*当光标离开iframe再进入时默认放在body的第1个节点上了,所以要记录光标的位置***/ if(!+"\v1"){ var bookmark; //记录IE的编辑光标 $.addEvent(iframe,"beforedeactivate",function(){//在文档失去焦点之前 var range = iframeDocument.selection.createRange(); bookmark = range.getBookmark(); }); //恢复IE的编辑光标 $.addEvent(iframe,"activate",function(){ if(bookmark){ var range = iframeDocument.body.createTextRange(); range.moveToBookmark(bookmark); range.select(); bookmark = null; } }); } /****************************************************************/ addSheet('\ #RTE_iframe{width:600px;height:300px;}\ #RTE_toolbar{float:left;width:600px;background:#D5F3F4;}\ #RTE_toolbar .button{display:block;float:left;border:1px solid #CCC;margin-left:5px;\ color:#000;background:#D0E8FC;height:20px;text-align:center;padding:0 10px;white-space: nowrap;}\ #RTE_toolbar select{float:left;height:20px;width:60px;margin-right:5px;}\ #RTE_toolbar .button:hover{color:#fff;border-color:#fff #aaa #aaa #fff;}\ div.fontpicker{display:none;height:150px;overflow:auto;position:absolute;\ border:2px solid #c3c9cf;background:#F1FAFA;}\ div.fontpicker a{display:block;text-decoration:none;color:#000;background:#F1FAFA;padding:2px;}\ div.fontpicker a:hover{color:#999;background:#e3e6e9;}\ div.colorpicker {display:none;position:absolute;width:216px;border:2px solid #c3c9cf;background:#f8f8f8;}\ div.colorpicker table{border-collapse:collapse;margin:0;padding:0;}\ div.colorpicker .cell td{height:12px;width:12px;}\ #color_result{width:216px;}\ #color_view{width:110px;height:25px;}\ div.tablecreator{display:none;width:176px;position:absolute;border:2px solid #c3c9cf;background:#f8f8f8;padding:1px;}\ div.tablecreator table{border:1px solid #69f;line-height:12px;font-size:12px;border-collapse:collapse;width:100%;}\ div.tablecreator td{font-size:12px;color:#777;text-align:center;}\ #rte_submit,#rte_cancel{font-size:12px;color:#777;border:1px solid #777;background-color:#f4f4f4;margin:5px 3px;}\ #rows, #cols, #width{width:80px;height:14px;line-height:12px;font-size:12px;border:1px solid #69f;}'); } } window.onload = function(){ new RichTextEditor({ id:'editor', textarea_id:'textarea' }); } </script> <title>富文本编辑器</title> </head> <body> <form action="#"> <textarea id="textarea" wrap="on"></textarea> </form> </body> </html>

运行代码

接着下来我们实现一下插入表情的功能。这个和上面插入表格没有什么不一样,只不过现在是插入IMG标签而已。关键的地方是如何保存图片的Url。


iconsHtml : function(){var builder = [];var j = 0;var _drawRow = function(builder,i){builder.push('<tr>');for(var i=0;i<6;i++){j++;_drawCell(builder,j);}builder.push('</tr>');}var _drawCell = function(builder,j){var url = 'http://images.cnblogs.com/cnblogs_com/rubylouvre/202906/o_face'+j+'.gif';builder.push('<td style="background:url('+url+') center center no-repeat; width:21px;height:21px;"');builder.push(' url="'+url+'"> </td>')/*★★★这里偷偷保存url★★★*/}builder.push('<table border=1>');for(var i=0 ;i<6;i++){_drawRow(builder,i);}builder.push('</table>');return builder.join('')},
var iconInsertor = $.CE('div');toolbar.appendChild(iconInsertor);iconInsertor.innerHTML = $.iconsHtml();iconInsertor.className = 'emoticons';//点击按钮显现表情插入器$.addEvent(toolbar['emoticons'],'click',function(){bind_select_event(this,iconInsertor);});$.addEvent(iconInsertor, 'click', function(e){var e = arguments[0] || window.event,current = e.srcElement ? e.srcElement : e.target,td = current.nodeName.toLowerCase();if(td == 'td'){var k = current.getAttribute("url");_insertHTML("<img src='"+k+"'/>");/*★★★取出url★★★*/iconInsertor.style.display = "none";}});

<!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"> #textarea {width:600px;height:300px;background:#F2F1D7;} </style> <script type="text/javascript"> var addSheet = function(){ var doc,cssCode; if(arguments.length == 1){ doc = document; cssCode = arguments[0]; }else if(arguments.length == 2){ doc = arguments[0]; cssCode = arguments[1]; }else{ alert("addSheet函数最多接受两个参数!"); } var headElement = doc.getElementsByTagName("head")[0]; var styleElements = headElement.getElementsByTagName("style"); if(styleElements.length == 0){/*如果不存在style元素则创建*/ if(!+"\v1"){ //ie doc.createStyleSheet(); }else{ var tempStyleElement = doc.createElement('style');//w3c tempStyleElement.setAttribute("type", "text/css"); headElement.appendChild(tempStyleElement); } } var styleElement = styleElements[0]; var media = styleElement.getAttribute("media"); if(media != null && !/screen/.test(media.toLowerCase()) ){ styleElement.setAttribute("media","screen"); } if(!+"\v1"){ //ie styleElement.styleSheet.cssText += cssCode; }else if(/a/[-1]=='a'){ styleElement.innerHTML += cssCode;//火狐支持直接innerHTML添加样式表字串 }else{ styleElement.appendChild(doc.createTextNode(cssCode)) } } var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } var RichTextEditor = Class.create();//我们的富文本编辑器类 RichTextEditor.prototype = { initialize:function(options){ this.setOptions(options); this.drawEditor(this.options.textarea_id); }, setOptions:function(options){ this.options = { //这里集中设置默认属性 id:'jeditor_'+ new Date().getTime(), textarea_id:null//用于textarea的ID,也就是我们的必选项 } extend(this.options, options || {});//这里是用来重写默认属性 }, ID:function(id){return document.getElementById(id) },//getElementById的快捷方式 TN:function(tn){ return document.getElementsByTagName(tn) },//getElementsByTagName的快捷方式 CE:function(s){ return document.createElement(s)},//createElement的快捷方式 fontPickerHtml:function(type,array){ var builder = []; for(var i = 0,l = array.length;i<l;i++){ builder.push('<a unselectable="on" style="'); if(type == 'fontname'){ builder.push('font-family'); builder.push(':'); builder.push(array[i]); /*呈现一行(一行就是一种字体)*/ builder.push(';" href="javascript:void(0)">'); builder.push(array[i]); }else if(type == 'fontsize'){ /*呈现一行(一行就是一种字号)*/ builder.push('font-size'); builder.push(':'); builder.push(array[i][1]); builder.push(';" sizevalue="'); builder.push(array[i][0]); builder.push('" href="javascript:void(0)">'); builder.push(array[i][2]); } builder.push("</a>"); } return builder.join(''); }, iconsHtml : function(){ var builder = []; var j = 0; var _drawRow = function(builder,i){ builder.push('<tr>'); for(var i=0;i<6;i++){ j++; _drawCell(builder,j); } builder.push('</tr>'); } var _drawCell = function(builder,j){ var url = 'http://images.cnblogs.com/cnblogs_com/rubylouvre/202906/o_face'+j+'.gif'; builder.push('<td style="background:url('+url+') center center no-repeat; width:21px;height:21px;"'); builder.push(' url="'+url+'"> </td>') } builder.push('<table border=1>'); for(var i=0 ;i<6;i++){ _drawRow(builder,i); } builder.push('</table>'); return builder.join('') }, tableHtml: function(){ var _drawInput = function(builder, name, value){ builder.push('<input id="'); builder.push(name); builder.push('" value="'); builder.push(value); builder.push('" />'); }; var builder = []; builder.push('<table>'); // 标题 builder.push('<tr><td colspan="2" style="padding:2px" bgcolor="#D0E8FC">'); builder.push('插入表格'); builder.push('</td></tr>'); // 行数 builder.push('<tr><td>行数</td><td>'); _drawInput(builder, 'rows', 3); builder.push('</td></tr>'); // 列数 builder.push('<tr><td>列数</td><td>'); _drawInput(builder, 'cols', 5); builder.push('</td></tr>'); // 宽度 builder.push('<tr><td>宽度</td><td>'); _drawInput(builder, 'width', 300); builder.push('</td></tr>'); // 提交 builder.push('<tr><td colspan="2" style="padding-top:6px;">'); builder.push('<input type="button" id="rte_submit" value="提交" unselectable="on" />'); builder.push('<input type="button" id="rte_cancel" value="取消" unselectable="on" />'); builder.push('</td></tr>'); builder.push('</table>'); return builder.join(''); }, //用于生成颜色选择器的具体内容 colorPickerHtml : function(){ var _hex = ['FF', 'CC', '99', '66', '33', '00']; var builder = []; // 呈现一个颜色格 var _drawCell = function(builder, red, green, blue){ builder.push('<td bgcolor="'); builder.push('#' + red + green + blue); builder.push('" unselectable="on"></td>'); }; // 呈现一行颜色 var _drawRow = function(builder, red, blue){ builder.push('<tr>'); for (var i = 0; i < 6; ++i) { _drawCell(builder, red, _hex[i], blue) } builder.push('</tr>'); }; // 呈现六个颜色区之一 var _drawTable = function(builder, blue){ builder.push('<table class="cell" unselectable="on">'); for (var i = 0; i < 6; ++i) { _drawRow(builder, _hex[i], blue) } builder.push('</table>'); }; //开始创建 builder.push('<table><tr>'); for (var i = 0; i < 3; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]); builder.push('</td>'); } builder.push('</tr><tr>'); for (var i = 3; i < 6; ++i) { builder.push('<td>'); _drawTable(builder, _hex[i]) builder.push('</td>'); } builder.push('</tr></table>'); builder.push('<table id="color_result"><tr><td id="color_view"></td><td id="color_code"></td></tr></table>'); return builder.join(''); }, addEvent:function(el, type, fn ) { if(!+"\v1") { el['e'+type+fn]=fn; el.attachEvent( 'on'+type, function() { el['e'+type+fn](); } ); }else{ el.addEventListener( type, fn, false ); } }, drawEditor:function(id){ var $ = this, textarea = this.ID(id), toolbar = this.CE('div'), br = this.CE('br'),//用于清除浮动 iframe = this.CE('iframe'); textarea.style.display = "none"; textarea.parentNode.insertBefore(toolbar,textarea); textarea.parentNode.insertBefore(br,textarea); textarea.parentNode.insertBefore(iframe,textarea); br.style.cssText = "clear:both"; toolbar.setAttribute("id","RTE_toolbar"); iframe.setAttribute("id","RTE_iframe"); iframe.frameBorder=0; var iframeDocument = iframe.contentDocument || iframe.contentWindow.document; iframeDocument.designMode = "on"; iframeDocument.open(); iframeDocument.write('<html><head><style type="text/css">body{ font-family:arial; font-size:13px;background:#DDF3FF;border:0; }</style></head></html>'); iframeDocument.close(); var buttons = {//工具栏的按钮集合 'removeFormat':'还原', 'bold': '加粗', 'italic': '斜体', 'underline': '下划线', 'strikethrough':'删除线', 'justifyleft': '居左', 'justifycenter': '居中', 'justifyright': '居右', 'indent':'缩进', 'outdent':'悬挂', 'forecolor':'前景色', 'backcolor':'背景色', 'createlink': '超链接', 'insertimage': '插图', 'fontname': '字体', 'fontsize': '字码', 'insertorderedlist':'有序列表', 'insertunorderedlist':'无序列表', 'table':'插入表格', 'emoticons':'插入表情', 'html':'查看' }; var fontFamilies = ['宋体','经典中圆简','微软雅黑', '黑体', '楷体', '隶书', '幼圆', 'Arial', 'Arial Narrow', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Georgia', 'New Roman Times', 'Verdana'] var fontSizes= [[1, 'xx-small', '最小'], [2, 'x-small', '特小'], [3, 'small', '小'], [4, 'medium', '中'], [5, 'large', '大'], [6, 'x-large', '特大'], [7, 'xx-large', '最大']]; var buttonClone = $.CE("a"), fragment = document.createDocumentFragment(); buttonClone.className = 'button'; for (var i in buttons){/*添加命令按钮的名字,样式*/ var button = buttonClone.cloneNode("true"); if(i == 'backcolor'){/*特殊处理背景色按钮*/ if (!+"\v1"){ button.setAttribute("title","background") }else{ button.setAttribute("title","hilitecolor") } } button.setAttribute("title",i);/*把execCommand的命令参数放到title*/ button.innerHTML = buttons[i]; button.setAttribute("unselectable", "on");/*防止焦点转移到点击的元素上,从而保证文本的选中状态*/ toolbar[i] = button; /*★★★★把元素放进一个数组,用于下一个循环绑定事件!★★★★*/ fragment.appendChild(button); } toolbar.appendChild(fragment); $.addEvent(toolbar, 'click', function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = target.getAttribute("title"); switch (command){ case 'createlink': case 'insertimage': var value = prompt('请输入网址:', 'http://'); _format(command,value); break; case 'fontname'://这六个特殊处理,不直接执行fontEdit命令! case 'fontsize': case 'forecolor': case 'backcolor': case 'html': case 'table': case 'emoticons': return; default://其他执行fontEdit(cmd, null)命令 _format(command,''); break; } }); /******************************************************************/ var fontPicker = $.CE('div'); fontPicker.className = "fontpicker"; toolbar.appendChild(fontPicker); /******************************************************************/ $.addEvent(toolbar['fontname'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontname',fontFamilies); fontPicker.style.width = "150px"; bind_select_event(this,fontPicker); }); /******************************************************************/ $.addEvent(toolbar['fontsize'], 'click', function(){ fontPicker.innerHTML = $.fontPickerHtml('fontsize',fontSizes); fontPicker.style.width = "100px"; bind_select_event(this,fontPicker); }); /******************************************************************/ $.addEvent(fontPicker,'click',function(){ var e = arguments[0] || window.event, target = e.srcElement ? e.srcElement : e.target, command = this.getAttribute("title"); var nn = target.nodeName.toLowerCase(); if(nn == 'a'){ var value; if('fontsize' == command){ value = target.getAttribute('sizevalue'); }else{ value = target.innerHTML; } _format(command,value); e.cancelBubble = true; fontPicker.style.display = 'none'; } }); /******************************************************************/ var colorPicker = $.CE('div'); toolbar.appendChild(colorPicker); colorPicker.className = "colorpicker"; colorPicker.innerHTML = $.colorPickerHtml(); /******************************************************************/ $.addEvent(toolbar['forecolor'],'click',function(){ bind_select_event(this,colorPicker); }); $.addEvent(toolbar['backcolor'],'click',function(){ bind_select_event(this,colorPicker); }); /******************************************************************/ $.addEvent(colorPicker,'mouseover',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(), colorView = $.ID('color_view'), colorCode = $.ID('color_code'); if( 'td' == nn){ colorView.style.backgroundColor = td.bgColor; colorCode.innerHTML = td.bgColor; } }); /******************************************************************/ $.addEvent(colorPicker,'click',function(){ var e = arguments[0] || window.event, td = e.srcElement ? e.srcElement : e.target, nn = td.nodeName.toLowerCase(); if(nn == 'td'){ var cmd = colorPicker.getAttribute("title"); var val = td.bgColor; _format(cmd,val); e.cancelBubble = true; colorPicker.style.display = 'none'; } }); /********切换回代码界面********************************************/ var _doHTML = function() { iframe.style.display = "none"; textarea.style.display = "block"; textarea.value = iframeDocument.body.innerHTML; textarea.focus(); }; /********切换回富文本编辑器界面*************************************/ var _doRich = function() { iframe.style.display = "block"; textarea.style.display = "none"; iframeDocument.body.innerHTML = textarea.value; iframe.contentWindow.focus(); }; /********切换编辑模式的开关*******************************************/ var switchEditMode = true; $.addEvent(toolbar['html'], 'click', function(){ if(switchEditMode){ _doHTML(); switchEditMode = false; }else{ _doRich(); switchEditMode = true; } }); /****************************************************************/ // iconInsertor.style.cssText = "display:none;width:150px;height:150px;background::#f8f8f8;position:absolute;"; //生成并隐藏表情插入器 var iconInsertor = $.CE('div'); toolbar.appendChild(iconInsertor); iconInsertor.innerHTML = $.iconsHtml(); iconInsertor.className = 'emoticons'; //点击按钮显现表情插入器 $.addEvent(toolbar['emoticons'],'click',function(){ bind_select_event(this,iconInsertor); }); $.addEvent(iconInsertor, 'click', function(e){ var e = arguments[0] || window.event, current = e.srcElement ? e.srcElement : e.target, td = current.nodeName.toLowerCase(); if(td == 'td'){ var k = current.getAttribute("url");/*★★★取出url★★★*/ _insertHTML("<img src='"+k+"'/>"); iconInsertor.style.display = "none"; } }); /******************************************************************/ var tableCreator = $.CE('div'); toolbar.appendChild(tableCreator); tableCreator.innerHTML = $.tableHtml(); tableCreator.className = 'tablecreator'; $.addEvent(toolbar['table'],'click',function(){ bind_select_event(this,tableCreator); }); $.addEvent(tableCreator, 'click', function(){ var e = arguments[0] || window.event, current = e.srcElement ? e.srcElement : e.target, submit = $.ID('rte_submit'), cancel = $.ID('rte_cancel'), rows = $.ID('rows').value, cols = $.ID('cols').value, width = $.ID('width').value; if(current==cancel) { this.style.display = 'none'; return; }else if(current==submit){ var html = _createTable(rows, cols, width); _insertHTML(html); this.style.display = "none"; } }); var _createTable = function(rows, cols, width){ var builder = []; builder.push('<table border="1" width="'); builder.push(width); builder.push('">'); for(var r = 0; r < rows; r++){ builder.push('<tr>'); for(var c = 0; c < cols; c++){ builder.push('<td> </td>'); } builder.push('</tr>'); } builder.push('</table>'); return builder.join(''); }; var _insertHTML = function(html){ iframe.contentWindow.focus(); if(!+"\v1"){ /****这里需要解决IE丢失光标位置的问题,详见核心代码四**************/ iframeDocument.selection.createRange().pasteHTML(html); }else{ var selection = iframe.contentWindow.getSelection(); var range; if (selection) { range = selection.getRangeAt(0); }else { range = iframeDocument.createRange(); } var oFragment = range.createContextualFragment(html), oLastNode = oFragment.lastChild ; range.insertNode(oFragment) ; range.setEndAfter(oLastNode ) ; range.setStartAfter(oLastNode ); selection.removeAllRanges();//清除选择 selection.addRange(range); } } /*******************核心代码之一******************************************/ /********************处理富文本编辑器的格式化命令**************************/ var _format = function(x,y){ try{ iframeDocument.execCommand(x,false,y); iframe.contentWindow.focus(); }catch(e){} } /***********核心代码之二*************************************************/ /***********隐藏与显示弹出层**********************************************/ var bind_select_event = function(button,picker){ button.style.position = 'relative'; var command = button.getAttribute("title"); if('backcolor' == command){ command = !+"\v1" ? 'backcolor':'hilitecolor'; } picker.setAttribute("title",command);//转移命令 if(picker.style.display == 'none'){ picker.style.display = 'block'; picker.style.left = button.offsetLeft + 'px'; picker.style.top = (button.clientHeight + button.offsetTop)+ 'px'; }else{ picker.style.display='none'; } } /*******************核心代码之三******************************************/ /**********************获取iframe的内容************************************/ $.addEvent(iframe.contentWindow,"blur",function(){ textarea.value = iframeDocument.body.innerHTML; }); /*******************核心代码之四******************************************/ /*当光标离开iframe再进入时默认放在body的第1个节点上了,所以要记录光标的位置***/ if(!+"\v1"){ var bookmark; //记录IE的编辑光标 $.addEvent(iframe,"beforedeactivate",function(){//在文档失去焦点之前 var range = iframeDocument.selection.createRange(); bookmark = range.getBookmark(); }); //恢复IE的编辑光标 $.addEvent(iframe,"activate",function(){ if(bookmark){ var range = iframeDocument.body.createTextRange(); range.moveToBookmark(bookmark); range.select(); bookmark = null; } }); } /****************************************************************/ addSheet('\ #RTE_iframe{width:600px;height:300px;}\ #RTE_toolbar{float:left;width:600px;background:#D5F3F4;}\ #RTE_toolbar .button{display:block;float:left;border:1px solid #CCC;margin-left:5px;\ color:#000;background:#D0E8FC;height:20px;text-align:center;padding:0 10px;white-space: nowrap;}\ #RTE_toolbar select{float:left;height:20px;width:60px;margin-right:5px;}\ #RTE_toolbar .button:hover{color:#fff;border-color:#fff #aaa #aaa #fff;}\ div.fontpicker{display:none;height:150px;overflow:auto;position:absolute;\ border:2px solid #c3c9cf;background:#F1FAFA;}\ div.fontpicker a{display:block;text-decoration:none;color:#000;background:#F1FAFA;padding:2px;}\ div.fontpicker a:hover{color:#999;background:#e3e6e9;}\ div.colorpicker {display:none;position:absolute;width:216px;border:2px solid #c3c9cf;background:#f8f8f8;}\ div.colorpicker table{border-collapse:collapse;margin:0;padding:0;}\ div.colorpicker .cell td{height:12px;width:12px;}\ #color_result{width:216px;}\ #color_view{width:110px;height:25px;}\ div.tablecreator{display:none;width:176px;position:absolute;border:2px solid #c3c9cf;background:#f8f8f8;padding:1px;}\ div.tablecreator table{border:1px solid #69f;line-height:12px;font-size:12px;border-collapse:collapse;width:100%;}\ div.tablecreator td{font-size:12px;color:#777;text-align:center;}\ #rte_submit,#rte_cancel{font-size:12px;color:#777;border:1px solid #777;background-color:#f4f4f4;margin:5px 3px;}\ #rows, #cols, #width{width:80px;height:14px;line-height:12px;font-size:12px;border:1px solid #69f;}\ div.emoticons {display:none;position:absolute;width:150px;height:150px;background::#f8f8f8;}'); } } window.onload = function(){ new RichTextEditor({ id:'editor', textarea_id:'textarea' }); } </script> <title>富文本编辑器</title> </head> <body> <form action="#"> <textarea id="textarea" wrap="on"></textarea> </form> </body> </html>

运行代码

好了,这部分就到此为止。下次再见!也请希望各位厚道点,多多推荐,多多讨论,让我的博客人气旺点!

一步步教你实现富文本编辑器(第四部分)相关推荐

  1. 一步步教你实现富本文编辑器(第二部分)

    <script type="text/javascript"> loadEvent(function(){ // guarder(); }) </script&g ...

  2. tinymce富文本编辑器做评论区

    今天分享一下tinymce富文本编辑器做评论区的全过程. 文章目录 一.介绍 1.最终效果 2.功能介绍 3.主要项目包版本介绍: 二.每个功能的实现 1.自定义toolbar的功能区 ①对应的样式以 ...

  3. 2021 年 React 的 5 大富文本编辑器

    5大富文本编辑器 今天,富文本编辑器被用于许多应用中,包括简单的博客和复杂的内容管理系统.然而,选择一个并不容易,因为有很多具有不同功能的编辑器. 因此,在这篇文章中,我将评估5个React的富文本编 ...

  4. 自己写富文本编辑器jss_JSS选择器和语法规则

    自己写富文本编辑器jss JSS is a JavaScript library that allows you to create objects that follow a CSS-like sy ...

  5. JavaWeb 富文本编辑器(Ckeditor)文件上传

    目录 一.什么是富文本编辑器? 二.CKEditor介绍 三.CKEditor下载 四.使用富文本编辑器 五.文件上传 一.什么是富文本编辑器? 富文本编辑器是一种可内嵌于浏览器,所见即所得的文本编辑 ...

  6. 富文本编辑器ueditor使用配置

    富文本编辑器(UEditor)       在平时开发Java Web项目的时候,往往会使用第三方插件来帮助我们更快的实现功能. 此文来自: 马开东云搜索 转载请注明出处 网址: http://mak ...

  7. Django下富文本编辑器Ueditor的配置和使用

    1.前言 "人生苦短,我用Python",Python作为一门"万能"的脚本语言,深受各个技术层级的程序猿的喜爱,而Django作为最受欢迎的Python的We ...

  8. .net下的富文本编辑器FCKeditor的配置方法(图)原创

    .net下的富文本编辑器FCKeditor的配置方法(图)原创 FCKeditor是一款开源的富文本编辑器,几乎支持所有流行的Web开发语言,版本稳定,用户多,可配置性好. 以前做Java和php的时 ...

  9. jeecg富文本编辑器增加字体(仿宋)

    jeecg富文本编辑器增加字体(仿宋) 温馨提示:jeecg 提供了 uedit 富文本的实现,如下针对的是 uedit 增加仿宋字体示例. 主要修改三个文件:plug-in\ueditor\uedi ...

最新文章

  1. 3最短路的几种解法 ------例题 最短路
  2. linux 软件装到hone,如何在Linux系统安装Apollo
  3. 一次expdp 错误的分析处理
  4. 并发之AQS原理(一) 原理介绍简单使用
  5. BZOJ 4278 [ONTAK2015]Tasowanie (后缀数组)
  6. c语言词法分析程序,词法分析器(c语言实现)
  7. 旗正规则引擎内存表出错的原因及解决方法
  8. nginx应用总结(1)--基础认识和应用配置
  9. iOS:延时执行的三种方式
  10. php按按字符串长度分割,支持中文的PHP按字符串长度分割成数组代码_PHP
  11. 太阳直射点纬度计算公式_利用旗杆影子——判断日出日落、季节、昼长、经纬度、太阳高度角...
  12. PS 导入笔刷和导入字体和导入滤镜
  13. Linux中使用宝塔面板部署tipask3.*超详细教程,吐血两天部署成功,把过程整理出来,送给被官方文档折磨的小白们~~~~
  14. 在MTK平台里,,函数kal_prompt_trace起什么作用???Kal_prompt_trace的参数有表示什么?...
  15. jsoup的简单实用兼谈一个简单的汇率查询(原创)
  16. shell脚本(linux)
  17. 从硬盘开始,一步步认识linux的文件系统
  18. python人脸识别门禁_树莓派人脸识别门禁系统图文教程
  19. MyBatis-Plus代码生成器(新)使用
  20. 深度知识的6个维度:如何让人工智能真正理解世界?

热门文章

  1. html将两张图重叠居中代码,【CSS技巧】多图片的垂直居中排版
  2. 剖析Elasticsearch集群系列之一:Elasticsearch的存储模型和读写操作
  3. 个人看法---团队合作
  4. 【C语言】中的版本规范(C89 C99等)
  5. 与Win8之磁盘活动时间100%斗争心得
  6. DevExpress.XtraGrid.Views.Grid.GridView 选中行焦点的滚动条的位置
  7. SWF反编神器Action Script Viewer终身免费升级!
  8. 如何利用期限来完成任务
  9. MySQL数据库安装Version5.7.25
  10. mysql数据库连接配置路径_关于mysql安装后更改数据库路径方法-linux环境