知识要求:1:熟悉dom结构层次(如childNodes,nodeType,parent,children)等。
2:熟悉jq对象转换js 对象,反之 毕竟不是专业js人。借助第3方框架。其实jq也是js封装的,所以请不要侮辱jq。
3:递归的使用(http://www.iteye.com/job/topic/1126012) iteye 深圳7k难找写递归的人 不知道大侠你们是怎么认为的。
4:学会调试js。工具 谷歌或者火狐 ie个人不习惯.
第1文本编辑器。http://www.cnblogs.com/rubylouvre/archive/2009/08/02/1537022.html(博客园司徒正美 听一个朋友说他是国内知名js高手具体也不清楚!)
最后我修改了下变成这个样子!
需求:
文本框输入文字,编辑 如果是颜色用F,字体用C,大小用S, 举个例子:
|F2,,C1,,w||F1,,博客园|| 首先F是字体的意思 ;C是颜色 ;S字体大小 里面的数字是具体属性。如颜色有红色,绿色 ;字体有12px ,14px ,20px (没有默认添加属性 这些都是自定义的),合起来的意思就是 "w"字体是宋体 颜色是红色 字体大小默认12px。同理博客园字体为宋体.
为了形象截下图。
还是直接上代码吧:
<script type="text/javascript"> var fontName = { ht: "黑体", kt: "楷体", yt: "幼圆", st: "宋体" }; var colorOhterHtml = { red: "#ff0000", lanSe: "#0000ff", hs: "#ffff00", ls: "#008000", bs: "#ffffff", qs: "#6a5acd", Black: "black" }; var colorIEHtml = { red: "red", green: "green", yellow: "yellow", blue: "blue", white: "white", Black: "#000000" }; $(function () { var content = $("#content"); new RichTextEditor({ id: 'editor', textarea_id: 'textarea' }); $("#btnValue").click(function () { var sEditValue = $("#RTE_iframe").contents().find("body").html().toLowerCase(); if (sEditValue == "") { alert("空"); return; } var txtDom = "<font><font><font color='black' face='宋体' size='1'>"; txtDom += sEditValue; txtDom += "</font></font></font>" $("#Div1").html("").append(txtDom); $("#div2").html("").append(txtDom); var dom = $("#Div1").children(); getTextNode($(dom)[0]); var textValue = getChildDom($(dom), 0); alert(textValue); }); //jquery结束 }); function fontCode(font) { var sCode = ""; switch (font) { case fontName.st: sCode += "\F0,,"; break; case fontName.ht: sCode += "\F1,,"; break; case fontName.kt: sCode += "\F2,,"; break; case fontName.yt: sCode += "\F3,,"; break; } return sCode; } function colorCode(color) { var sCode = ""; switch (color) { case colorOhterHtml.Black: case colorIEHtml.Black: sCode += "\C0,,"; break; case colorOhterHtml.red: case colorIEHtml.red: sCode += "\C1,,"; break; case colorOhterHtml.ls: case colorIEHtml.blue: sCode += "\C2,,"; break; case colorOhterHtml.hs: case colorIEHtml.yellow: sCode += "\C3,,"; break; case colorOhterHtml.qs: case colorIEHtml.blue: sCode += "\C6,,"; break; case colorOhterHtml.ls: case colorIEHtml.green: sCode += "\C4,,"; break; case colorOhterHtml.bs: case colorIEHtml.white: sCode += "\C7,,"; break; } return sCode; } function sizeCode(size) { var sCode = ""; switch (size) { case "1": sCode += "\S0,,"; break; case "2": sCode += "\S1,,"; break; case "3": sCode += "\S2,,"; break; case "4": sCode += "\S3,,"; break; case "5": sCode += "\S4,,"; break; case "6": sCode += "\S5,,"; break; case "7": sCode += "\S6,,"; break; case "8": sCode += "\S7,,"; break; } return sCode; } function getChildDom(dom) { var lastCode = ""; for (var i = 0; i < dom.length; i++) { if ($(dom[i]).children().length > 0) { var baseDomObj = $(dom[i]); var childText = getChildDom(baseDomObj.children()); if (!baseDomObj.is('font')) { continue; } var baseText = baseDomObj.html(); baseDomObj.replaceWith("|?" + baseText + "|?"); lastCode += baseText; baseText = "|?" + baseText + "|?"; } else { var childDomObj = $(dom[i]); if (!childDomObj.is('font')) { continue; } var childrenText = childDomObj.html(); childrenText = "|?" + childrenText + "|?"; childDomObj.replaceWith(childrenText); } } return lastCode; } function getColorVal(dom) { if ($(dom).parent('font')[0] != null && typeof ($(dom).parent('font')[0]) != 'undefined') { var color = $($(dom).parent('font')[0]).attr("color"); if (typeof (color) == "undefined") { var colVal = getColorVal($(dom).parent('font')[0]); if (typeof (colVal) == "undefined") { return colVal; } } else { return color; } } } function getFontVal(dom) { if ($(dom).parent('font')[0] != null && typeof ($(dom).parent('font')[0]) != 'undefined') { var font = $($(dom).parent('font')[0]).attr("face"); if (typeof (font) == "undefined") { var fontVal = getFontVal($(dom).parent('font')[0]); if (typeof (fontVal) == "undefined") { return fontVal; } } else { return font; } } } function getSizeVal(dom) { if ($(dom).parent('font')[0] != null && typeof ($(dom).parent('font')[0]) != 'undefined') { var size = $($(dom).parent('font')[0]).attr("size"); if (typeof (size) == "undefined") { var sizeVal = getSizeVal($(dom).parent('font')[0]); if (typeof (sizeVal) == "undefined") { return sizeVal; } } else { return size; } } } function getTextNode(dom) { var oElement = dom.childNodes; for (var i = 0; i < oElement.length; i++) { if (oElement[i].nodeType == 3 && typeof (oElement[i]) != "undefined") { if (oElement[i].nodeType == 3) { var color = getParentNodeColor(oElement[i]); var size = getParentNodeSize(oElement[i]); var face = getParentNodeFace(oElement[i]); var colorCd = colorCode(color); var sizeCd = sizeCode(size); var faceCd = fontCode(face); $(oElement[i]).replaceWith(colorCd + sizeCd + faceCd + oElement[i].nodeValue); } } else { getTextNode(oElement[i]); } } } function getParentNodeColor(txtNode) { if (typeof (txtNode.parentNode) != "undefined" && txtNode.parentNode.nodeType == 1) { var color = getColorVal(txtNode); if (color != '') { return color; } else { color = getParentNodeColor(txtNode.parentNode); } } else { color = getParentNodeColor(txtNode.parentNode); } return color; } function getParentNodeSize(txtNode) { if (typeof (txtNode.parentNode) != "undefined" && txtNode.parentNode.nodeType == 1) { var size = getSizeVal(txtNode); if (size != '') { return size; } else { size = getParentNodeSize(txtNode.parentNode); } } else { size = getParentNodeSize(txtNode.parentNode); } return size; } function getParentNodeFace(txtNode) { if (typeof (txtNode.parentNode) != "undefined" && txtNode.parentNode.nodeType == 1) { var face = getFontVal(txtNode); if (face != '') { return face; } else { face = getParentNodeFace(txtNode.parentNode); } } else { face = getParentNodeFace(txtNode.parentNode); } return face; } function delHtmlTag(str) { return str.replace(/<[^>]+>/g, ""); } </script>
html:
<html> <head> <script src="jquery-1.3.1.js" type="text/javascript"></script> <script src="textEdit.js" type="text/javascript"></script> <style type="text/css"> #textarea { width: 378px; height: 97px; background: #F2F1D7; } </style> <title>富文本编辑器</title> </head> <body> <form action="#"> <textarea id="textarea" wrap="on"></textarea> <br /> <textarea id="tsp" wrap="on" style=" 626px; height: 200px;"></textarea> <input type="button" id="btnValue" value="获取值" /> <div id="content"> </div> <div id="Div1"> </div> <div id="div2"> </div> </form> </body> </html>
textEdit.js代码:(注)修改博客园司徒的
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 class="aFont" 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('" sizevalue="'); builder.push(array[i][0]); builder.push('" href="javascript:void(0)">'); builder.push(array[i][2]); } builder.push("</a>"); } return builder.join(''); }, fontClorHtml: function (type, array) { var builder = []; var sText; for (var i = 0, l = array.length; i < l; i++) { builder.push('<a class="aFontColor" unselectable="on" style="'); if (type == 'forecolor') { builder.push('color'); builder.push(':'); builder.push(array[i]); builder.push(';" href="javascript:void(0)">'); builder.push(array[i]); } builder.push("</a>"); } 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><body></body></html>'); iframeDocument.close(); var buttons = {//工具栏的按钮集合 'forecolor': '颜色', 'fontname': '字体', 'fontsize': '字码' }; var fontFamilies = ['宋体', '黑体', '楷体', '幼圆', '扩展字体']; var fontColors = ["黑色", "红色", "绿色", "黄色", "蓝色", "品红", "青色", "白色", "斑点", "条纹"]; var fontSizes = [[1, '8px', '8'], [2, '12px', '12'], [3, '16px', '16'], [4, '24px', '24'], [5, '32px', '32'], [6, '40px', '40'], [7, '48px', '48'], [8, '56px', '56']]; 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 'fontname': //这六个特殊处理,不直接执行fontEdit命令! case 'forecolor': case 'fontsize': 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 = "60px"; fontPicker.setAttribute("id", "fontPicker"); bind_select_event(this, fontPicker); }); /******************************************************************/ var fontPicker = $.CE('div'); fontPicker.className = "fontpicker"; toolbar.appendChild(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 fontColor = $.CE('div'); fontColor.className = "fontColor"; toolbar.appendChild(fontColor); $.addEvent(toolbar['forecolor'], 'click', function () { fontColor.innerHTML = $.fontClorHtml('forecolor', fontColors); fontColor.style.width = "60px"; fontColor.style.height = "80px"; fontColor.setAttribute("id", "fontColor"); bind_select_event(this, fontColor); }); /******************************************************************/ var fontColor = $.CE('div'); fontColor.className = "fontColor"; toolbar.appendChild(fontColor); $.addEvent(fontColor, '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; if (value === "黑色") { value = "black"; } else if (value === "红色") { value = "red"; } else if (value === "绿色") { value = "Green"; } else if (value === "黄色") { value = "Yellow"; } else if (value === "蓝色") { value = "Blue"; } else if (value === "品红") { value = "bule"; } else if (value === "青色") { value = "SlateBlue"; } else if (value === "白色") { value = "White"; } else if (value === "斑点") { value = "bule"; } else if (value === "条纹") { value = "bule"; } } _format(command, value); e.cancelBubble = true; fontColor.style.display = 'none'; } }); /******************************************************************/ $.addEvent(toolbar['fontsize'], 'click', function () { fontPicker.innerHTML = $.fontPickerHtml('fontsize', fontSizes); fontPicker.style.width = "80px"; bind_select_event(this, fontPicker); }); /******************************************************************/ 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"); 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; } }); } /**********************************************************fontpicker******/ addSheet(' #RTE_iframe{600px;height:300px;} #RTE_toolbar{float:left;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;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;216px;border:2px solid #c3c9cf;background:#f8f8f8;} div.colorpicker table{border-collapse:collapse;margin:0;padding:0;} div.colorpicker .cell td{height:12px;12px;} div.fontColor{display:none;height:60px;overflow:auto;position:absolute; border:2px solid #c3c9cf;background:#F1FAFA;} div.fontColor a{display:block;text-decoration:none;color:#000;background:#F1FAFA;padding:2px;} div.fontColor a:hover{color:#999;background:#e3e6e9;} div.fontColor {display:none;position:absolute;60px;border:2px solid #c3c9cf;background:#f8f8f8;} div.fontColor table{border-collapse:collapse;margin:0;padding:0;} div.fontColor .cell td{height:12px;12px;}'); } }
个人总结:dom是 如此的强大和优美,所以请不要随便说精通javascript.递归是一种思路和算法(这里用了8个递归 当然大部分思路一样!)。
关于递归借用我朋友的话 如果你项目里面有2个for 一般就可以尝试递归。
优点:把字符串转换成dom节点处理可以避免浏览器差役, 不要永远想着大规模去处理字符串 .当然这个功能的完成也求助了我的朋友!
吐槽一句 后台出身的人却喜欢前端技术。
最后感谢大家的阅读 希望能看的懂的朋友 如果觉得有意义帮忙推荐下 谢谢!