JavaScript Iframe富文本编辑器中的光标定位

最近在项目中碰到一个比较棘手的问题:

  在iframe富文本编辑器中,有个工具栏,这个工具栏在iframe标签之外,工具栏上有一个按钮,点击该按钮向iframe正在编辑中的光标处插入一个图片,图片会插入到当前光标所在的位置。但由于需求的需要,点击该按钮后需要弹出一个详细选项浮动层,选择详细的类型后再插入,如此,问题来了,当我点击了该按钮,浮动层显示出来后,iframe已经失去焦点,并不知道之前正在编辑的位置,所以编辑器默认把图片插入到编辑器内容的最前边(内部处理),编辑器及浮动层需求如下图:

解决尝试

一、利用模态弹出框

  首先声明这种方式是可行的,因为模态对话框会保持iframe编辑器的编辑状态,模态对话框的返回值可直接插入到之前正在编辑的光标位置,就像上面图中其他按钮一样,它们通过点击事件直接插入。但是对于上述需求,只是在该按钮位置添加了一个子类型选择列表框,用模态窗口显然得不到更好的人性化体验,这也不是我们所想要的。

  这时候如果能保存之前光标的编辑位置就好了,的确,在按钮的点击事件中,弹出浮动层的同时也保存好光标的位置,然后选择了详细类型后再将光标还原到原来的位置插入图片信息,经过尝试和摸索,令人欣喜的是,这种方式是可行的。

二、保存光标位置,选择后还原(1)

  这种方法主要通过document的selection对象来实现,在按钮的点击事件处理程序中,获取当前光标据文档开头的位置(即长度),然后保存,在选择了子类型后,根据之前保存的位置还原光标,然后插入图片信息,代码片段如下:

 1 //记录光标的位置,以备后续还原使用
 2 var LastPos = 0;
 3 //保存当前光标的位置
 4 function SaveCusorPos() {
 5     //获取编辑器焦点
 6     var wobj = document.getElementById("myiframe").contentWindow;
 7     wobj.focus();
 8     if (document.selection) {
 9         //ie,利用范围进行计算
10         var sText = wobj.document.selection.createRange();
11         //清除掉当前选中的内容
12         if (sText.htmlText != undefined && sText.htmlText != "") {
13             wobj.document.selection.clear();
14         }
15         //选择当前光标位置到文档开头之间的内容(以字符为单位)
16         sText.moveStart('character', -wobj.document.body.innerHTML.toString().length);
17         //计算选择内容的长度
18         LastPos = sText.text.length + FliterHtmlTag(sText.htmlText) + 1; //; //sText.htmlText.length; //
19     }
20     else if (wobj.selectionStart || wobj.selectionStart == "0") {
21         //firefox,直接读取编辑位置
22         LastPos = wobj.selectionStart;
23     }
24 }

上述代码不难理解,在ie中需要用范围计算当前光标位置距离文档开头的距离,而在firefox中,直接可以用编辑对象获取当前的编辑位置,下面是光标还原的代码:

 1 //把光标还原到之前保存的位置
 2 function SetCusorPos() {
 3     //获取编辑器对象焦点
 4     var wobj = document.getElementById("myiframe").contentWindow;
 5     wobj.focus();
 6     if (wobj.document.body.setSelectionRange) {
 7         //firefox,直接通过函数定位光标
 8         wobj.document.body.setSelectionRange(LastPos, LastPos);
 9     }
10     else if (wobj.document.selection.createRange()) {
11         //ie,用selection对象进行选择
12         var range = wobj.document.selection.createRange();
13         range.collapse(true);
14         //将选择区域的开始位置和结束位置都移动到之前保存的点
15         range.moveEnd('character', LastPos);
16         range.moveStart('character', LastPos);
17         //定位光标的位置
18         range.select();
19     }
20 }

在不同的浏览器中,处理方式均不一样,不过有一点是相通的,它们都是通过将选取的开始位置和结束位置重合来定位光标。

  经测试,这种方式是可行的,但它只能在纯文本处理的时候有用(IE中),问题在于这个保存点的计算,通过选区Text的length获取的长度是只是这个选区的文字长度,它并不能过滤多媒体元素(如图片、音视频等),这些元素在这个length中并没有包括,故存在多媒体元素的时候,这个光标保存点是不准的,会在实际位置的前面插入。此外,选区还有另外一个属性htmlText,获取它的长度又如何呢!?答案也是不行,这个长度包含了选区中html标签的所有字符,比如换行,段落等都被计算在内,这个光标保存点比实际的要大的多,会在实际位置的后面插入。

二、保存光标位置,选择后还原(2)

  上述两种方法都有自己的缺陷,经过摸索和查阅相关资料,在IE中有第三种方法可以实现此功能,就是selection对象的getBookmarkmoveToBookmark两个方法,前者获取一个对象,这个对象记录了当前编辑器中光标的位置信息,后者根据这个位置信息还原光标的位置。代码如下:

 1 //存储之前光标位置信息的对象
 2 var ieSelectionBookMark = null;
 3 //保存当前光标的位置
 4 function SaveCusorPos() {
 5     //编辑器获取焦点
 6     var wobj = document.getElementById("myiframe").contentWindow;
 7     wobj.focus();
 8     if (document.selection) {
 9         //获取当前光标的位置
10         var rangeObj = wobj.document.selection.createRange();
11         ieSelectionBookMark = rangeObj.getBookmark();
12     }
13 }
14 //把光标还原到之前保存的位置
15 function SetCusorPos() {
16     //编辑器获取焦点
17     var wobj = document.getElementById("myiframe").contentWindow;
18     wobj.focus();
19     if (ieSelectionBookMark) {
20         //还原光标的位置
21         var rangeObj = wobj.document.selection.createRange();
22         rangeObj.moveToBookmark(ieSelectionBookMark);
23         rangeObj.select();
24         ieSelectionBookMark = null;
25     }
26 }

上述代码改写了第二种方法中的两个函数,比较简洁,但这种方式在IE8中测试通过,其他不同版本浏览器中有待进一步验证,其他浏览器如firefox,利用第二种方式就可以实现。

 

如今浏览器五法八门,各自对标准的支持也不一样,导致了前端开发者做了大量的工作来弥补兼容性,不管怎样,相信会越来越好~~~

转载于:https://www.cnblogs.com/freshfish/p/3432907.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值