zoukankan      html  css  js  c++  java
  • 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,利用第二种方式就可以实现。

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

  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/freshfish/p/3432907.html
Copyright © 2011-2022 走看看