自己写html editor

简单的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');
			}
		}

Total views.

© 2013 - 2024. All rights reserved.

Powered by Hydejack v6.6.1