可编辑的DIV -编辑器
找了好多,没几个好用的,都或多或少有问题
目前这个最好用。。 不过有一个奇葩的问题,就是要放在"<a></a>"标签里面, js或者jQuery获取 $("#list a").click() 就可以了。。。
$("#list a").click(function(){ var oBtn = "<button contenteditable='false'>@ "+ $(this).find(".name").text() +"</button>"; $("#oEditor").focus(); insertHtmlAtCaret(oBtn); });
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Div编辑器</title> <style type="text/css"> #editor {width:500px;height:200px;border:1px solid #ccc;margin:20px 0;padding:10px;} </style> </head> <body> <div id="editor" contenteditable="true">这是一个输入框...</div> <a href="javascript:;" id="active">插入文字</a> <a href="javascript:;" id="active2">插入btn</a> <a href="javascript:;" id="active3">插入图片</a> <script type="text/javascript"> function insertHtmlAtCaret(html) { var sel, range; if (window.getSelection) { // IE9 and non-IE sel = window.getSelection(); if (sel.getRangeAt && sel.rangeCount) { range = sel.getRangeAt(0); range.deleteContents(); // Range.createContextualFragment() would be useful here but is // non-standard and not supported in all browsers (IE9, for one) var el = document.createElement("div"); el.innerHTML = html; var frag = document.createDocumentFragment(), node, lastNode; while ((node = el.firstChild)) { lastNode = frag.appendChild(node); } range.insertNode(frag); // Preserve the selection if (lastNode) { range = range.cloneRange(); range.setStartAfter(lastNode); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); } } } else if (document.selection && document.selection.type != "Control") { // IE < 9 document.selection.createRange().pasteHTML(html); } } window.onload = function(){ var oEditor = document.getElementById("editor"); var oActive = document.getElementById("active"); var oActive2 = document.getElementById("active2"); var oActive3 = document.getElementById("active3"); oActive.onclick = function(){ oEditor.focus(); insertHtmlAtCaret("555"); } oActive2.onclick = function(){ oEditor.focus(); insertHtmlAtCaret("<button>tttt</button>"); } oActive3.onclick = function(){ oEditor.focus(); insertHtmlAtCaret("<img src='http://mat1.gtimg.com/www/images/qq2012/qqlogo_1x.png' width='134' />"); } } </script> </body> </html>
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Div编辑器</title> <style type="text/css"> a {text-decoration:none;color:#555;} #editor {width:500px;height:200px;border:1px solid #ccc;margin:20px 0;padding:10px;} li {display:inline;line-height:30px;margin-right:20px;font-size:14px;} li span {display:inline-block;zoom:1;vertical-align:middle;} button {background:none;border:none;} </style> </head> <body> <div id="editor" contenteditable="true">这是一个输入框...</div> <!-- <a href="javascript:;" id="active">插入文字</a> <a href="javascript:;" id="active2">插入btn</a> <a href="javascript:;" id="active3">插入图片</a> --> <ul id="list"> <li> <a href="javascript:;"> <span class="head"><img src="http://qlogo3.store.qq.com/qzone/619611422/619611422/30?1349166380" alt=""></span> <span class="name">小名</span> </a> </li> <li> <a href="javascript:;"> <span class="head"><img src="http://qlogo3.store.qq.com/qzone/619611422/619611422/30?1349166380" alt=""></span> <span class="name">林兆禄</span> </a> </li> <li> <a href="javascript:;"> <span class="head"><img src="http://qlogo3.store.qq.com/qzone/619611422/619611422/30?1349166380" alt=""></span> <span class="name">小红</span> </a> </li> <li> <a href="javascript:;"> <span class="head"><img src="http://qlogo3.store.qq.com/qzone/619611422/619611422/30?1349166380" alt=""></span> <span class="name">小张</span> </a> </li> </ul> <script type="text/javascript" src="http://s.rc.umfun.com//view/javascript/jQuery191_v1.js"></script> <script type="text/javascript"> function insertHtmlAtCaret(html) { var sel, range; if (window.getSelection) { // IE9 and non-IE sel = window.getSelection(); if (sel.getRangeAt && sel.rangeCount) { range = sel.getRangeAt(0); range.deleteContents(); // Range.createContextualFragment() would be useful here but is // non-standard and not supported in all browsers (IE9, for one) var el = document.createElement("div"); el.innerHTML = html; var frag = document.createDocumentFragment(), node, lastNode; while ((node = el.firstChild)) { lastNode = frag.appendChild(node); } range.insertNode(frag); // Preserve the selection if (lastNode) { range = range.cloneRange(); range.setStartAfter(lastNode); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); } } } else if (document.selection && document.selection.type != "Control") { // IE < 9 document.selection.createRange().pasteHTML(html); } } $(function(){ $("#list a").click(function(){ var oBtn = "<button contenteditable='false'>@ "+ $(this).find(".name").text() +"</button>"; $("#oEditor").focus(); insertHtmlAtCaret(oBtn); }); }); /*window.onload = function(){ var oEditor = document.getElementById("editor"); var aActive = document.getElementById("list").getElementsByTagName("li"); for(var i=0; i<aActive.length; i++){ aActive[i].onclick = function(){ var oBtn = "<button contenteditable='false'>@ "+ this.innerHTML +"</button>"; oEditor.focus(); insertHtmlAtCaret(oBtn); } } }*/ </script> </body> </html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>光标控制器</title> <script type="text/javascript"> function cursorControl(a){ this.element=a; this.range=!1; this.start=0; this.init(); }; cursorControl.prototype={ init:function(){ var _that=this; this.element.onkeyup=this.element.onmouseup=function(){ this.focus(); if(document.all){ _that.range=document.selection.createRange(); }else{ _that.start=_that.getStart(); } } }, getType:function(){ return Object.prototype.toString.call(this.element).match(/^\[object\s(.*)\]$/)[1]; }, getStart:function(){ if (this.element.selectionStart || this.element.selectionStart == '0'){ return this.element.selectionStart; } // else if (window.getSelection){ // var rng = window.getSelection().getRangeAt(0).cloneRange(); // rng.setStart(this.element,0); // return rng.toString().length; // } }, insertText:function(text){ this.element.focus(); if(document.all){ document.selection.empty(); this.range.pasteHTML(text) //this.range.text = this.range.pasteHTML(text); this.range.collapse(); this.range.select(); } else{ if(this.getType()=='HTMLDivElement'){ //this.element.innerHTML=this.element.innerHTML.substr(0,this.start)+text+this.element.innerHTML.substr(this.start); // Begain of The Content added by bedweather var sel = window.getSelection(); var rang = sel.rangeCount > 0 ? sel.getRangeAt(0) : null; if (rang == undefined || rang == null || (rang.commonAncestorContainer.id !="editdiv" && rang.commonAncestorContainer.parentNode.id !="editdiv")){ this.element.focus(); rang = document.createRange(); rang = selectNode(this.element); rang.setStart(range.getEndContainer, rang.endOffset); } rang.deleteContents(); rang.insertNode(rang.createContextualFragment(text)); var tempRange = document.createRange(); var a = document.getElementById("editdiv") tempRange.selectNodeContents(a); if(rang.commonAncestorContainer.id == "editdiv"){ tempRange.setStart(rang.endContainer, rang.endOffset+1); tempRange.setEnd(rang.endContainer, rang.endOffset+1); } else { tempRange.setStartAfter(rang.endContainer.nextSibling); tempRange.setEndAfter(rang.endContainer.nextSibling); } sel.removeAllRanges(); sel.addRange(tempRange); this.element.focus(); // End of The Content added by bedweather }else{ this.element.value=this.element.value.substr(0,this.start)+text+this.element.value.substr(this.start); }; } }, getText:function(){ if (document.all){ var r = document.selection.createRange(); document.selection.empty(); return r.text; } else{ if (this.element.selectionStart || this.element.selectionStart == '0'){ var text=this.getType()=='HTMLDivElement'?this.element.innerHTML:this.element.value; return text.substring(this.element.selectionStart,this.element.selectionEnd); } else if (window.getSelection){ return window.getSelection().toString() }; } } }; var c1,c2; window.onload=function(){ c1=new cursorControl(document.getElementById('text')); c2=new cursorControl(document.getElementById('editdiv')); }; function fn1(str){ c1.insertText(str); }; function fn2(str){ c2.insertText(str); }; function fn3(){ alert(c1.getText()); }; function fn4(){ alert(c2.getText()); } </script> </head> <body> <input type = "button" value = "插入字符串 {文本1}" onclick="fn1('{文本1}');"/><input type = "button" value = "获取选中的文本" onclick="fn3();"/><br /> <br /> <textarea id="text" cols="50" rows="5">这里是文本框</textarea><br /><br /> <input type = "button" value = "插入字符串 {文本2}" onclick="fn2('{文本2}');"/> <input type = "button" value = "获取选中的文本" onclick="fn4();"/><br /> <br /> <input type = "button" value = "插入图片" onclick="fn2('<img src=\'http://s1.hao123img.com/index/images/newlogo-186X68.png\'/> ');"/> <input type = "button" value = "获取选中的文本" onclick="fn4();"/><br /> <br /> <div id="editdiv" contentEditable="true">这里是一个可编辑层</div><br /> </body> </html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Language" content="zh-cn" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>DIV可编辑框鼠标光标处插入图片或者文字。</title> <script type="text/javascript" src="http://www.w3school.com.cn/jquery/jquery.js "></script> <script type="text/javascript"> $(function(){ $(".imgbox img").click(function(){ $("#testdiv").focus(); var sy = $(".imgbox img").index(this) + 1; var img_url = "<img src='faceimg/"+sy+".gif'>"; /*此处如果不是插入图片可这样: var img_url = "插入测试的文字"; */ _insertimg(img_url); }) //注:如果要插入的是那种“快捷发言,快捷留言”里的文字,只需把那些文字都分别放在A标签里即可,然后img_url=a标签里面的内容。工作中的编辑器终于搞定!能插入图片和快捷发言和表情图片等。 }) //监控粘贴(ctrl+v),如果是粘贴过来的东东,则替换多余的html代码,只保留<br> function pasteHandler(){ setTimeout(function(){ var content = document.getElementById("testdiv").innerHTML; valiHTML=["br"]; content=content.replace(/_moz_dirty=""/gi, "").replace(/\[/g, "[[-").replace(/\]/g, "-]]").replace(/<\/ ?tr[^>]*>/gi, "[br]").replace(/<\/ ?td[^>]*>/gi, " ").replace(/<(ul|dl|ol)[^>]*>/gi, "[br]").replace(/<(li|dd)[^>]*>/gi, "[br]").replace(/<p [^>]*>/gi, "[br]").replace(new RegExp("<(/?(?:" + valiHTML.join("|") + ")[^>]*)>", "gi"), "[$1]").replace(new RegExp('<span([^>]*class="?at"?[^>]*)>', "gi"), "[span$1]").replace(/<[^>]*>/g, "").replace(/\[\[\-/g, "[").replace(/\-\]\]/g, "]").replace(new RegExp("\\[(/?(?:" + valiHTML.join("|") + "|img|span)[^\\]]*)\\]", "gi"), "<$1>"); if(!$.browser.mozilla){ content=content.replace(/\r?\n/gi, "<br>"); } document.getElementById("testdiv").innerHTML=content; },1) } //锁定编辑器中鼠标光标位置。。 function _insertimg(str){ var selection= window.getSelection ? window.getSelection() : document.selection; var range= selection.createRange ? selection.createRange() : selection.getRangeAt(0); if (!window.getSelection){ document.getElementById('testdiv').focus(); var selection= window.getSelection ? window.getSelection() : document.selection; var range= selection.createRange ? selection.createRange() : selection.getRangeAt(0); range.pasteHTML(str); range.collapse(false); range.select(); }else{ document.getElementById('testdiv').focus(); range.collapse(false); var hasR = range.createContextualFragment(str); var hasR_lastChild = hasR.lastChild; while (hasR_lastChild && hasR_lastChild.nodeName.toLowerCase() == "br" && hasR_lastChild.previousSibling && hasR_lastChild.previousSibling.nodeName.toLowerCase() == "br") { var e = hasR_lastChild; hasR_lastChild = hasR_lastChild.previousSibling; hasR.removeChild(e) } range.insertNode(hasR); if (hasR_lastChild) { range.setEndAfter(hasR_lastChild); range.setStartAfter(hasR_lastChild) } selection.removeAllRanges(); selection.addRange(range) } } //监控按enter键和空格键,如果按了enter键,则取消原事件,用<BR/ >代替。此处还等待修改!!!!!!如果后端能实现各个浏览器回车键产生的P,div, br的输出问题话就无需采用这段JS、 function enterkey(){ e = event.keyCode; if (e==13||e==32) { var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode; event.returnValue = false; // 取消此事件的默认操作 if(document.selection && document.selection.createRange){ var myRange = document.selection.createRange(); myRange.pasteHTML('<br />'); }else if(window.getSelection){ var selection = window.getSelection(); var range = window.getSelection().getRangeAt(0); range.deleteContents(); var newP = document.createElement('br'); range.insertNode(newP); } //alert(document.getElementById("testdiv").innerHTML) } } </script> <style type="text/css"> .editbox{width:400px;height:200px;border:1px solid #000; overflow-x:hidden; overflow-y:auto; outline:none;} .editbox img{ margin:0 3px; display:inline;} </style> </head> <body> <div id="testdiv" contenteditable="true" class="editbox" onkeydown="enterkey()" >可以在任意文字后面插入图片或者文字哦!<br /></div> <div class="imgbox"> <img src="faceimg/1.gif"> <img src="faceimg/2.gif"> <img src="faceimg/3.gif"> <img src="faceimg/4.gif"> </div> <script type="text/javascript"> //此处必须防止在最下端。 var edt = document.getElementById("testdiv"); if(edt.addEventListener){ edt.addEventListener("paste",pasteHandler,false); }else{ edt.attachEvent("onpaste",pasteHandler); } </script> </body> </html>
下面这两个插入图片有点问题。
If all you want to do is insert some content at the cursor, there's no need to find its position explicitly. The following function will insert a DOM node (element or text node) at the cursor position in all the mainstream desktop browsers:
function insertNodeAtCursor(node) { var range, html; if (window.getSelection && window.getSelection().getRangeAt) { range = window.getSelection().getRangeAt(0); range.insertNode(node); } else if (document.selection && document.selection.createRange) { range = document.selection.createRange(); html = (node.nodeType == 3) ? node.data : node.outerHTML; range.pasteHTML(html); } }
If you would rather insert an HTML string:
function insertHtmlAtCursor(html) { var range, node; if (window.getSelection && window.getSelection().getRangeAt) { range = window.getSelection().getRangeAt(0); node = range.createContextualFragment(html); range.insertNode(node); } else if (document.selection && document.selection.createRange) { document.selection.createRange().pasteHTML(html); } }
UPDATE
Following the OP's comments, I suggest using my own Rangy library, which adds a wrapper to IETextRange
object that behaves like a DOM Range. A DOM Range consists of a start and end boundary, each of which is expressed in terms of a node and an offset within that node, and a bunch of methods for manipulating the Range. The MDC article should provide some introduction.
http://stackoverflow.com/questions/2213376/how-to-find-cursor-position-in-a-contenteditable-div
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <script> //插入话题 function inTopic(id, str){ var str = str || "请在这里输入自定义话题"; str = "#" + str + "#"; var reg = new RegExp(str), oTextarea = document.getElementById(id), oValue = oTextarea.value, val_index = 0, val_match, val_pos; if(reg.test(oValue)){ val_match = oValue.match(reg); val_index = val_match.index; } else{ val_pos = getTextPos(oTextarea); val_index = val_pos.start; rangeText(oTextarea, str); } selectText(oTextarea, val_index + 1, val_index + str.length - 1); } //光标的当前位置 function getTextPos(obj){ if(!obj || obj.offsetWidth == 0){ return false; } var t = obj, start = 0, end = 0, value = '', range, range_all; value = t.value; if(typeof(t.selectionStart) == "number"){ start = t.selectionStart; end = t.selectionEnd; } else if(document.selection && t.offsetWidth>0){ t.focus(); range = document.selection.createRange(); if(range.parentElement() == t){ range_all = document.body.createTextRange(); range_all.moveToElementText(t); for(start = 0; range_all.compareEndPoints("StartToStart", range) < 0; start++){ range_all.moveStart('character', 1); } for(var i = 0; i <= start; i++){ if(t.value.charAt(i) == '\n'){ start++; } } range_all.moveToElementText(t); for(end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; end++){ range_all.moveStart('character', 1); } for(var i = 0; i <= end; i++){ if(t.value.charAt(i) == '\n'){ end++; } } } } else{ start = value.length; end = value.length; } return{ start: start, end: end } } //光标处替换的文本 function rangeText(obj, val, num){ if(!obj || obj.offsetWidth == 0){ return false; } var t = obj, start = 0, end = 0, value = '', val_start = '', val_end = '', pos; var userAgent = navigator.userAgent.toLowerCase(), ie = /msie/.test(userAgent) && !/opera/.test(userAgent); if(ie && t.nodeName.toLocaleLowerCase() != 'textarea'){ t.value = val; t.focus; return; } value = t.value; pos = getTextPos(t); start = pos.start; end = pos.end; if (typeof num=='number'){ start = start - num; } val_start = value.substring(0, start); val_end = value.substring(end); t.value = val_start + val + val_end; if (typeof num=='number'){ end = end - num; } selectText(t,end+val.length,end+val.length); } //光标定位到指定文本 function selectText(obj, start, stop){ if(!obj || obj.offsetWidth == 0){ return false; } var range; if(obj.setSelectionRange){ obj.setSelectionRange(start,stop); } else{ range = obj.createTextRange(); range.collapse(true); range.moveStart("character",start); range.moveEnd("character",stop-start); range.select(); } obj.focus(); } </script> <style type="text/css"> body{margin:0;background-image:url(miaov.jpg);} .box{width:600px;height:200px;background:url(weibo.png) no-repeat;margin:60px auto;position:relative;} #textarea{ border: medium none;font-size: 14px;height: 70px;line-height: 124%;padding: 0;width: 475px;overflow:hidden;resize: none;position:absolute;left:62px; top:55px;outline: none;} .button{width:100px;height:30px;background:url(button.gif) 0 0 no-repeat;position:absolute;left:442px;top:135px;} .button:hover{background-position:0 -30px;} .button:active{background-position:0 -60px;} .topic{position:absolute;left:72px;top:136px;height:26px;line-height:26px;text-decoration:none;color:#fff;font-size:12px;background:url(topic.gif) no-repeat 0 7px;padding-left:14px;} </style> </head> <body> <div class="box"> <textarea id="textarea" accesskey="1" tabindex="1" style="font-family: Tahoma,宋体;"></textarea> <a href="http://www.miaov.com" class="button"></a> <a href="###" class="topic" onclick="inTopic('textarea','妙味课堂')">话题</a> </div> </body> </html>