富文本兼容性问题归纳(win)

上周抽空把去年写的富文本重写了一下,封装成基本UI组件,就可以在聊天框之外的地方复用了。个人觉得富文本是个兼容问题最多的模块之一,尤其是文档也没几个,把mozilla的api文档和IE的dom api关于selection和range的看了一个遍,一个个试,总算找到勉强能用的方法。

其实之前的富文本代码太乱,而且还有不少bug,只是产品经理不给时间改,O__O”…

这个富文本没有用iframe来做输入框,原因有二:

  1. iframe是所有dom节点中消耗性能最大的,开多几个ie6/7就会卡到不行了;
  2. 因为webqq是多窗口聊天的,当光标点击到输入框时,iframe会捕获鼠标事件,通知不了聊天窗设置样式;

所以就用了div,设置contentEditable=”true”,这个属性基本浏览器都支持,除了firefox2.0(不过还真有用户还在用ff2.0⊙﹏⊙b汗)

这次修改发现了不少蛋疼的兼容性问题,挑几个归纳一下:

1. 光标位置的保存/还原

富文本很大一部分兼容问题在于保存和还原光标的位置。说起光标位置,有个要注意的地方就是不要随便调用focus方法,连续调用两次focus会导致光标失去, 跟调用blur的效果一样,最好的方式就是让调用方在调用的时候保证光标在输入框中,内部代码中不要调用focus。

保存就不说了,keyup/mouseup的时候把当前的range存起来(这里有性能问题,但是blur事件又不能用,产生这个事件的时候,光标已经移到别处了),但是要保证光标在输入框中,否则range就是document的。

这里要注意到是,ie9支持了window.getSelection方法,但是,它拿到的range对象没有createContextualFragment方法,这个方法可以传入一个html字符串,直接生成dom节点,跟pasteHTML有点类似,具体说明可以点击这里查看。因此自己封装的getSelection方法,要把document.selection放在前面。

还原光标位置,对于高级浏览器,直接把原来的range添加到selection就行,像这样

双击选中源代码

1

2

selection.removeAllRanges();

selection.addRange(this._lastRange);

ie则有两种方法:

  1. getBookmark和moveToBookmark

    双击选中源代码

    1

    2

    3

    var range = RichEditor.getRange();

    range.moveToBookmark(this._lastBookmark);

    range.select();

  2. setEndPoint
    双击选中源代码

    1

    2

    3

    4

    range.setEndPoint(‘EndToStart‘, this._lastRange);

    range.collapse(false);

    range.setEndPoint(‘EndToEnd‘, this._lastRange);

    range.select();

这里说下setEndPoint的原理:

  1. 先保存lastRange,如”ABCDEFG”中的”CDE”
  2. 把新的range的结尾移动到lastRange的开头(即”C”的左边)
  3. 然后调用 collapse(false)把光标的插入点移动到range的结尾,也就是把range的开头和结尾合并在一起,不这样处理的话,调用select之后会选中”AB”(即选中”C”之前的所有内容)
  4. 把range的结尾移动到lastRange的结尾(即”E”的右边)
  5. 选中该range就能把上次保存的选区还原了(即选中”CDE”)

2. 换行处理

当在输入框按下回车键之后,ie会生成一个新的<p></p>段落标签,ff是<br>,chrome则是<div></div>。这也不是什么大问题,但是会让后续的处理产生麻烦, 理想的情况就是任何浏览器里输入框的内容都一样。所以这里要监控输入框的keydown事件,如果是回车,则阻止浏览器的默认行为,使用代码插入一个换行标签<br>。

注意1: opera的keydown事件是没办法阻止默认行为的,要用keypress事件代替。

注意2:当chrome的光标在一行的末尾的时候,插入一个<br/>并不能让光标移动到下一行,还需要在<br/>后面插入一个额外的节点才能跳到下一样。因此可以先插入<br/>&nbsp;,然后把html空格”&nbsp;”删除即可。

3. 删除处理(ie)

ie中如果选中一个图片或input等节点,按下退格键的话,会触发浏览器的后退处理,跟调用history.back()一样的效果,可以在keydown的时候判断选中内容的类型,如果是control类型,则阻止浏览器的行为,使用代码删除。

双击选中源代码

1

2

3

4

5

var selection = RichEditor.getSelection();

if (selection.type.toLowerCase() === ‘control‘) {

    e.preventDefault();

    selection.clear();

}

PS: 这种情况只存在于使用div做输入框的情况,iframe没有。

4. 粘贴&拖拽处理

聊天窗的输入框跟一般的富文本不太一样,想发表文章用的富文本,是可以允许粘贴html片段进来的。但是聊天框里贴入html片段会导致样式很乱,影响体验。而且里面的图片都必须先上传到服务器才能使用。因此要对贴入的内容进行过滤。

之前的处理是直接把所有内容用正则过滤一遍,放过<br>和部分有标识的标签,其余一概删掉,然后再重新插入输入框。这样处理比较简单,但是会导致过滤后的光标无法找回原来的地方,体验不好。

现在是用遍历dom的方法,遍历输入框的直接子节点,把其中的文本提取出来,创建TextNode,并替换掉它的父节点,这里用到两个比较重要的属性:

  1. textContent(标准浏览器): textContent保存了它所有的子孙节点的文本,去除了所有Element节点
  2. innerText(ie): ie没有textContent属性,但是可以用innerText代替

注意: opera没有onpaste事件,只能捕捉到ctrl+v的粘贴行为,而且很意外的keypress的v键keyCode 还是86。右键贴入的就没办法了,连编辑的div连oninput事件也触发不了 O__O”…

5. 插入处理

标准浏览器(非ie)要在光标处插入内容,可以用range.createContextualFragment创建一个html片段,调用range.insertNode插入。用这种方法插入后,光标会消失,要把光标重新定位显示。

双击选中源代码

1

2

3

4

5

6

7

8

9

var fragment = range.createContextualFragment(html);

var lastNode = fragment.lastChild;

range.insertNode(fragment);

//插入后把开始和结束位置都放到lastNode后面, 然后添加到selection

range.setEndAfter(lastNode);

range.setStartAfter(lastNode);

var selection = RichEditor.getSelection();

selection.removeAllRanges();

selection.addRange(range);

ie就简单多了, 虽然也不见得是什么好事

双击选中源代码

1

2

3

range.pasteHTML(html);

range.collapse(false);

range.select();

6. 插入后的光标定位

插入html片段后,如果出现了滚动条,在非ie浏览器里,光标已经在可视区下面,而且不会自动滚动到可视区域。解决办法是插入html片段的时候,在后面添加多一个宽高都是0的图片,然后计算图片相对输入框的位置是否已经超出了输入框的可视范围。如果是,将输入框滚动定位到图片处,之后将图片删除。

这里之所以用图片,是因为他是display: inline;的元素,不会导致内容换行,又可以设置宽高,让其对用户不可见,是在是杀人越货必备之品。

代码如下:

JavaScript

1

2

3

4

5

6

7

8

html += ‘<img class="focus_mark" />‘;

var fragment = range.createContextualFragment(html);

var lastNode = fragment.lastChild;

//..........

var divArea = this._divArea;

var pos = $D.getRelativeXY(lastNode, divArea);

divArea.scrollTop = pos[1] < divArea.scrollHeight ? divArea.scrollHeight : pos[1];

document.execCommand(‘Delete‘, false, null);// 删除附加的节点

这里也可以用lastNode.scrollIntoView()滚动到可视区域的, 只是ff如果打开了firebug, 会导致webqq的样式错乱, 其他网站也许可以测试看看.

7. 保证range在输入框中

前面很多方法的执行前提都是当前焦点在输入框中,否则如果焦点在document上的话,插入的html会显示在页面的左上角,就是一个大bug了。

判断一个range是否在输入框中,可以对range的父节点进行判断,如果其parentNode是输入框或者在输入框里面,则是正确的range。 标准浏览器可以用range.commonAncestorContainer获得父节点,ie则是range.parentElement()。比较的方法是compareDocumentPosition(w3c)和contains(ie),具体怎么用就不说了,这里有个说明及封装好的代码。

以上的问题都是windows平台的,linux上也有问题,但是还没测,待续…

时间: 2024-08-08 13:30:29

富文本兼容性问题归纳(win)的相关文章

百度editor富文本编辑器在火狐浏览器中的兼容性

最近做项目的时候遇到了百度的一个神器:editor富文本编辑器.但是也遇到了很多兼容性的问题,现在写一段随笔一起分享一下: 第一:在火狐浏览器中,该编辑器部分的编辑功能按钮不能显示 可以看出,在火狐浏览器中只会显示编辑框,而上面的编辑按钮缺没有.(但是在IE7,IE8上不能显示的原因在于新版本中屏蔽了 anonymous()方法,可以通过修改eWebEditor的JS文件来修正错误) 解决方案:打开火狐-->工具栏-->“工具”-->"添加附件",使用搜索功能来搜索“

富文本编辑器开发原理

富文本编辑器的开发主要使用到东西如下: 1.iframe 2.将iframe的designMode设置为'on' 3.将iframe的contentEditable设置为true 4.获取iframe对象的contentDocument(注意兼容性) 5.使用contentDocument对象的write方法写入一个html文档,为解决兼容性问题需要再使用write方法之前使用open方法.之后使用close方法. 6.获取文档内容使用doc.body.innerHTML 7.实现加粗之类操作的

扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计

扩展于RCLabel的支持异步加载网络图片的富文本引擎的设计 在iOS开发中,图文混排一直都是UI编程的一个核心点,也有许多优秀的第三方引擎,其中很有名的一套图文混排的框架叫做DTCoreText.但是在前些日的做的一个项目中,我并没有采用这套框架,原因有二,一是这套框架体积非常大,而项目的需求其实并不太高:二是要在这套框架中修改一些东西,难度也非常大,我最终采用的是一个叫做RCLabel的第三方控件,经过一些简单的优化和完善,达到了项目的要求. 先来介绍一下我项目中的图文混排的需求:首先我从服

富文本编辑器的一些要点

重新复习了富文本编辑器的基本实现,现总结下要点: 1,iframe的创建,之所以使用iframe框架,是为了防止编辑的内容影响当前文档. 2,隐藏的textarea保存iframe的源码 3,ie下的兼容性,为了保存ie的选中范围,需要借助于textRange.getBookmark(),以及ie特有的onbeforedeactivate和onactivate 事件.onbeforedeactivate事件触发条件:焦点从当前活动对象转移到同一个document的另一个对象时触发,它和onblu

SpringMvc + Jsp+ 富文本 kindeditor 进行 图片ftp上传nginx服务器 实现

一:html 原生态的附件上传 二:实现逻辑分析: 1.1.1 需求分析 Common.js 1.绑定事件 2.初始化参数 3.上传图片的url: /pic/upload 4.上图片参数名称: uploadFile 5.返回结果数据类型json 参考文档: http://kindeditor.net/docs/upload.html 返回格式(JSON) 1 //成功时 2 3 { 4 5 "error" : 0, 6 7 "url" : "http://

重构wangEditor(web富文本编辑器),欢迎指正!

1. 前言 (下载源码.使用说明.demo,请参见:https://github.com/wangfupeng1988/wangEditor) 前段时间做过一个基于bootstrap的富文本编辑器--wangEditor,并发布到github上(https://github.com/wangfupeng1988/wangEditor),在博客园写了篇文章(http://www.cnblogs.com/wangfupeng1988/p/4088229.html)也受到了不少关注. 之所以有这次重构

web项目中nicedit富文本编辑器的使用

一.为什么要用富文本编辑器? 先说什么是富文本编辑器吧,普通的html中input或textarea标签只能进行简单的输入,而做不到其他的文本调整功能,甚至 连空格与回车都要另写工具类去识别,更谈不上字体大小和颜色的修改.整体排版都功能了.其实一般读入文段类型的输入框都需 要富文本编辑器,没错,你们平时写博客用的就是富文本编辑器.如果还是无法理解富文本与普通输入框的区别,请看下图:  二.为什么要选nicedit 同类富文本编辑器有很多,这里选nicedit来说并不是因为它有多好,反而它功能并不

wysiwyg富文本数据如何保存到mysql

bootstrap提供了一个叫wysiwyg的富文本组件,用来显示和编辑富文本数据,但如何将编辑后的数据保存到mysql数据库,却不得而知.另外,如何将mysql数据库中的数据显示到wysiwyg也不得而知,对于这两个问题,让我来告诉你解决方案! 一.效果展示 首先,我们先来看看效果如何: 富文本中有一张图片,还有一个数字列表 我们可以看到编辑后的数据保存成功,以及保存后对应的展示. 二.富文本 度娘对于富文本的解释如下: 富文本格式(Rich Text Format, 一般简称为RTF)是由微

ueditor百度富文本编辑器使用解决方案

写网站的时候都是用asp.net2.0写的 但是看了百度的富文本编辑器使用说明都是.net framework 4.0 版本的 百度了半天看的各种的解决方案 我把最新版本的百度富文本编辑器下载下来 改了.sln 文件信息 可以用vs2008打开 当然会报一些错误 ..类名不存在等等 百度了半天还是没解决问题后来放弃了.(最终还是用了百度的) 于是就找了kindeditor但是觉得他长得有点丑..还是放弃了 又接着百度ueditor配置方法看到了一篇博文 http://blog.sina.com.