自己写html editor
in Web前端 on java, web html css 前端 - Hits()
简单的html editor 就是利用iframe的 document属性 designMode = 'on' 来让iframe可编辑。
如下例:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>自己写Html编辑器</title> <script type="text/javascript"> function init() { var doc = document.getElementById("EditForm").contentWindow.document; doc.designMode = 'on'; doc.write('<html><head><title></title><style type="text/css">p {margin: 0;padding: 0;}</style></head><body>fffffffffffffffffffff</body></html>'); doc.close(); } </script> </head> <body onLoad="init()"> <iframe id="EditForm" frameborder="0" style="width: 700px; height: 400px; padding: 0; margin: 0; border: 1px solid #AAAAAA"> </iframe> </body> </html>
在IE和opera下,回车形成的行之间是用<p>(FF 下是<br>,chrome,safari是<div>)来包含的,造成行间距太大,因此要使用样式来修正。
第一次设置designMode为on会将document本来的内容全部清除。所以需要将样式表等初始化内容写入文档。
inserAtCursor插入文本实现:
IE使用TextRange.pasteHTML
其他使用selectionRange.deleteFromDocument 清空 //opera不起作用,使用Range.deleteContents
使用selectionRange.addRange添加内容
Range.createContextualFragment创建html
Range.inserNode添加节点(节点必须已经存在dom中,否则报错,但是createContextualFragment不存在这个问题)
然而createContextualFragment无法得到Dom节点对象,
insertNode中可以使用DocumentFragment
而selectNode则不行,最终只好换回使用createElement再转移。
但是selectNode在FF,opera下ok,在safari和chrome下就不行了。
只好将插入的内容放入span中,直接对这个span节点selectionRange.selectAllChildren,然后selectionRange.collapseToEnd。
虽然加入了额外的span节点,总算是实现了。
但是看到ext的htmlEditor源码,真是哭笑不得,IE的做的做法和我的一样(Ext的实现有bug)
其他浏览器的一句话搞定doc.execCommand('InsertHTML', false, html);直接略过上述碰到的种种问题。
还是把自己写的留下来做个纪念吧
this.insertAtCursor1 = function(html) { this.focus(); if (isIE) { if (!cursel) { cursel = doc.selection.createRange(); } cursel.pasteHTML(html); cursel.collapse(false); cursel.select(); } else { var r = win.getSelection(); if (r.toString().length) { r.deleteFromDocument(); } if (!r.rangeCount) { r.addRange(doc.createRange()); } else { // opera r.getRangeAt(0).deleteContents(); } var rg = r.getRangeAt(0); var tc = doc.createElement('span'); tc.innerHTML = html; doc.body.appendChild(tc); rg.insertNode(tc); //webkit必须要这样才能将光标移到刚插入内容的末尾,Range.collapse(false)不起作用 //但是这样造成连续调用insertAtCursor的话,会使刚插入的内容插入到上次创建的span里面嵌套了 //这种实现不好 r.selectAllChildren(tc); r.collapseToEnd(); } };
换行事件:
opera要取消回车事件默认处理的话,除了在keydown里面要调用preventDefault之外,在keypress里面也得调用,否则不起效果(就算stopPropagation,cancelBubble也一样)。
这里使用insertAtCursor(‘<br>’)的方法不能达到换行的目的:
FF,opera不起作用,
其余倒是可以但是调用doc.innerText就得不到换行了。
这时到可以使用上面的selection方法了:
this.newLine = function() { this.focus(); if (isIE) { if (!cursel) { cursel = doc.selection.createRange(); } cursel.text = '\n'; cursel.collapse(false); cursel.select(); } else { if (cox.isOpera || cox.isGecko) { var r = win.getSelection(); if (r.toString().length) { r.deleteFromDocument(); } if (!r.rangeCount) { r.addRange(doc.createRange()); } else { // opera r.getRangeAt(0).deleteContents(); } var rg = r.getRangeAt(0); var tc = doc.createElement('br'); doc.body.appendChild(tc); rg.insertNode(tc); /** * opera下这样写反而到导致光标没有移动,不写倒是ok的, * 火狐必须这样写,但是有个bug,如果开始什么都没有内容就换行会导致光标没换行(其实已经插入br了), * 火狐这种写法还导致getText忽略了换行 * */ if (cox.isGecko) { rg.selectNode(tc); rg.collapse(false); r.collapseToEnd(); } } else if (cox.isWebKit) { doc.execCommand('InsertText', false, '\n'); } }