在线编辑器实现原理 2

2012年4月2日 发表评论 阅读评论

大家可以看到sohu的blog在发表文章时所用的编辑器,实际上是对一个iframe进行编辑,当iframe的designMode设定为On时,即成为可编辑状态。看下面的代码:

//for ie

document.frames['iframe'].document.designMode = ‘On’;

//for firefox

document.getElementById("iframe").contentDocument.designMode = ‘On’;

对于,文字加粗,斜体,设定字体这些,一般是用一个名为execCommand的方法,比如,文字加粗:

var editor = document.getElementById("iframe").contentDocument; //for firefox

if(editor == null) editor = document.frames['iframe'].document;

editor.execCommand("bold", false, null);

上面这段代码,即是将指定iframe内所选中文字进行加粗。我们要探讨的重点并不在此,在IE和firefox中存在的诸多不同,比如将指定 iframe内所选中文字加超链接,在execCommand中提供了方法,但是仅仅对IE有效,firefox无法使用,这是我们今天探讨的主要问题:

range对象在IE和firefox中的使用

为所选中的文字加超链接,首先想到的就是要获得所选中的内容并将其替换为带有<a>标签的html代码。这一点,即使不使用execCommand,那么在IE中也很容易做到的:

[上面的代码已经定义了变量editor,这里不再定义,直接使用]

var oRange = edtr.selection.createRange(); //创建一个range

var selectTxt = oRange.text; //获得所选中的文字

var linkHtml = ‘<a href="http://asers.blog.sohu.com">’+selectTxt+’</a>’; //要插入的html代码

oRange.pasteHTML(linkHtml); //将html代码粘贴回原位并替换所选内容。

上面的代码对ie简单有效,但是在firefox下面却无法执行,那么我们单独来看firefox。

在firefox中获得所选内容可以使用getSelection()方法,但是这里有一个误区,看下面的代码:

var selectTxt = edtr.getSelection(); //我们上面定义过edtr为document.getElementById("iframe").contentDocument

alert(selectTxt);

那么你可以看到,他确实返回了你所选择的内容,但是当我们需要创建一个range的时候:

var selection = edtr.getSelection().getRangeAt(0); //注意这里与ie的不同

那么这个时候就出现错误了。我们也看到了,edtr为contentDocument,即文档对象,而range则是窗口对象,那么我们应该使用iframe的窗口对象,即contentWindow,看下面的代码:

var selection = document.getElementById("iframe").contentWindow.getRangeAt(0);

这个时候就不会出现错误了,而我们如果用上面提到的方法同样alert一下这段代码的结果:

alert(document.getElementById("iframe").contentWindow.getSelect());

那么你会看到,它实际上与使用contentDocument时是完全一样的。而不同的是,后者可以创建range。既然创建了range,那么我们就可以使用range对象所包含的方法:[Range].surroundContents()为所选内容加超链接:

var selection = document.getElementById("iframe").contentWindow.getRangeAt(0);

var linkElement = edtr.createElement("a"); //创建一个新的<A>节点

linkElement.href = "http://asers.blog.sohu.com";//设置<A>节点的href属性

selection.surroundContents(linkElement);//加入超链接

到这里,功能已经完全实现了,下面附上surroundContents()方法的介绍:

========================================================================

[Range].surroundContents()

[说明]用指定节点包围范围内的内容

[参数]newParent应当为docObj.createElement()所创建的节点对象或其他方法返回的节点对象

[描述]该方法将当前范围的父节点重新定为:newParent,然后把newParent插入到文档中范围的开始位置。

========================================================================

{//HtmlEditor target 预替换的 textarea 节点id
function HtmlEditor(target) {
if (!(target = document.getElementById(target))) return false;
var iframe = document.createElement(‘iframe’);
this.textarea = target;
this.iframe = iframe;
var iframeTextContent = ”
iframeTextContent += ‘<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">’
iframeTextContent += ‘<html xmlns="http://www.w3.org/1999/xhtml" >’;
iframeTextContent += ‘<head> <title>text edit area</title>’;
iframeTextContent += ‘<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />’;
iframeTextContent += ‘<link rel="stylesheet" type="text/css" href="../css/mxjia_config.css" /></head>’;
iframeTextContent += ‘<body style="padding:3px;margin:0px;font-size:12px;cursor:text;text- align:left;line-height:16px;">测试</body></html>’;
this.iframeTextContent = iframeTextContent;
}

HtmlEditor.prototype = {
//获取TextArea对象
getTextArea: function() {
return this.textarea;
},
//获取iframe对象
getIframe: function() {
return this.iframe;
},
//获取iframe引用的子窗体对象
getWin: function() {
return this.iframe.contentWindow;
},
//获取iframe引用窗体对象的document对象
getDoc: function() {
return this.getWin().document;
},
//获取iframe应用窗体的body对象
getBox: function() {
return this.getDoc().body;
},
//开启document对象的 DesignModel
openDocDesignMode: function() {
try {
this.getDoc().open();
this.getDoc().write(this.iframeTextContent);
this.getDoc().close();
this.getDoc().designMode = ‘on’;
}
catch (e) {
setTimeout(arguments.callee, 10);
}
},
//创建并初始化iframe对象
init: function() {
this.iframe.id = ‘iframe_’ + this.textarea.id || ‘iframe_htmlEditor’;
this.iframe.className = this.textarea.className;
mxjia.insertAfter(this.iframe, this.textarea);
this.textarea.style.display = ‘none’;
this.openDocDesignMode();
alert(this.getDoc().body); //这里 在ie中 打印出 null 其他浏览器全部正常….
}

}
}
//========
ie里要先打开 设计模式 再输出 内容 . 才能找到document.body 对象

this.getDoc().designMode = ‘on’;
this.getDoc().open();
this.getDoc().write(this.iframeTextContent);
this.getDoc().close();


转载请注明来自:[MSN Spaces]http://msn.shandian.biz/217.html

  1. 本文目前尚无任何评论.