论坛首页 AJAX版 JavaScript

可编辑iframe的换行问题的解决(绕远了...)

浏览 495 次
精华帖 (0) :: 良好帖 (7) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2008-07-15 关键字: iframe换行问题
最近由于公司要开发一套OA系统,OA系统中有一个在线交流聊天的功能.本来想直接用textarea进行实现.不过由于不支持图片,不支持表情.用起来体验太差.于是选用可编辑的iframe进行实现.
但以前本人从没接触过这方面的东东,本来以为弄个可编辑的iframe,再弄几个插入图片,插入表情等等东西就可以了,不过一开始就遇到问题了.在iframe中单击换行的时候,iframe中会自动的将当前行包含在一个<p>标签中.可众所周知,<p>标签中,换行的行距那也忒大了.看着就不舒服.有什么好的解决办法呢?
开始时,我想的是截取键盘的点击事件,让按Enter键时的点击失效.然后在当前光标处添加一个<br />标签.可这个<br />要怎么插入呢.突然想起以前看到过的一个方法
document.execCommand("paste");
这个方法就可以在光标所在处,插入剪帖版中的内容.近而联想到window对象中的clipboardData对象.不是可以直接设置剪贴版中的内容的方法么:
window.clipboardData.setData("Text","value");
于是有了本人的第一个解决方案:
<script>
window.onload=function(){
    MyEditor.document.designMode="on";
    MyEditor.document.onkeypress=function(){return keyPress(MyEditor.event);};
}
function keyPress(ev){
    if(ev.keyCode==13){
        //将剪贴版中的文本内容设置成为换行符\n.(在可编辑状态下\n代表的就是<br />);
        window.clipboardData.setData("Text","\n");
        //执行粘贴操作.
        document.execCommand("paste");
        //使点击Enter按钮失效.
        return false;
    }
    return true;
}
</script>
<iframe id="MyEditor" name="MyEditor" style="width:400;height:400;font-size:12px;" frameborder=0 src="">
</iframe>

可这样一来.换行是成功了,可我剪贴版中的内容怎么办呢?于是我又想到了clipboardData对象的getData();方法于是我在将剪贴版内容替换为\n之前.将里面的内容给提取出来.
var oldData=window.clipboardData.getData("Text");
在执行粘贴操作后,再将它的值给设置回去.
window.clipboardData.setData("Text",oldData);
可每次执行它都会报错:OpenClipBoard失败.到MSDN上一看,才知道如果连续执行两次setData()操作.会出现一些无法控制的错误...
这让我想起了曾经的一个IE特性,在新创建一个input标签之后,无法直接让它获取焦点.和这个问题有那么一点点相似性.
在这里,我再一次认识到了延迟时间为0秒的setTimeout的威力:
    if(ev.keyCode==13){
        //将内容提取出来
         var oldData=window.clipboardData.getData("Text");
        //将剪贴版中的文本内容设置成为换行符\n.
        window.clipboardData.setData("Text","\n");
        //执行粘贴操作.
        document.execCommand("paste");
        //加上setTimeout之后,设置前贴版内容成功了.- -!无语...
        setTimeout(function(){
            window.clipboardData.setData("Text",oldData);
        },"0");
        //使点击Enter按钮失效.
        return false;
    }


OK,没错,可以正确执行了.IE没问题了.火狐呢?一试,郁闷了.window.clipboardData对象在FF中不支持,execCommand方法在FF中不支持.哎..写了半天,白写了.又要重头开始了,那有没有别的什么解决办法呢?

于是本人发挥了Baidu+Google神功,不是有一句话么,叫知之为知之,不知则百度(Google)知.可百度(Google)也不是万能的.搜了半天.全是同样的解决方案.而且还是个有BUG的解决方案,没有一个是真正可以直接拿来使用的.真不知道,这种解决方案怎么在网上流传得这么广,难道真是IT界没人才了?顺便在这里BS一下那些见到什么内容就抄的网站.麻烦转文章时看一下这样的文章值不值得转载,OK?

不过搜到的内容还是给了我一些小提示,让我发现了一些以前没有用到过的方法和属性:
1>document.selection,获取文档中的选中部分,如果没有,则得到的是光标所在的地点.
2>createRange(),document.selection的一个方法,用于将选中处设置为一个区域,然后对区域中的内容进行操作.
于是又写了一个解决方案:
if(ev.keyCode==13){
    //将选中区域的内容设置为\n,即<br />标签.
    BenEditor.document.selection.createRange().text="\n";
    //让事件失效
    return false; 
}

按理说应该是可以实现换行了,可iframe偏偏跟我作对,插入了一个\n之后.由于光标还是处于createRange()所形成的区域中.实际换行已经成功,<br />标签也已经生成了.但光标却没有换行.只是往后空出了一小块地方.我猜想,这一块空间,应该就是\n这个字符所形成的吧.那当我执行完成之后,把光标向后移一位,这样,不就实现了文档中换行,光标也接着换行吗?
在Google和DHTML文档的帮助下.终于完成了最后的解决方案:
<script>
window.onload=function(){
    MyEditor.document.designMode="on";
    MyEditor.document.onkeypress=function(){return keyPress(MyEditor.event);};
}
function keyPress(ev){
    if(ev.keyCode==13){
        //在光标所在处创建一个区域.
        var range=BenEditor.document.selection.createRange();
        //将区域的内容设置成为换行符.
        range.text="\n";
        //将区域的起始点向右移动一个字符的长度.
        range.moveStart("character", 1);
        //将光标移动到区域的结尾.(若为false则是移动到起始位置).
        range.collapse(true);
        //由于上面的一系列操作,使得区域的位置处在了\n之后,所以再次选择时,光标就到了新一行的结尾.完成换行.
        range.select();
        //使事件失效
         return false; 
    }
    return true;
}
</script>
<iframe id="MyEditor" name="MyEditor" style="width:400;height:400;font-size:12px;" frameborder=0 src="">
</iframe>


到IE下测试,没问题,再跑到FF底下运行,同样没错!绕了几个弯之后,在iframe中换行的问题终于得到了成功的解决.

-----------------------------------------------------------------------------------------------
这个问题可能并不常见,也没多少人会遇到.
但我发这个帖子是想把自己发现问题和找问题的过程写出来,跟大家一起分享.共同成长.
如果写的有问题,也欢迎指出.
-----------------------------------------------------------------------------------------------
后话:
绕了半天弯.才发现,原来解决换行问题不用这么麻烦的.
直接在iframe中,把p的css属性改一下.使用:
p
{
    margin:0px;
    padding:0px;
}
就可以实现了.
强烈的BS自己...并感谢Quake Wang的提示.
不过多走了这么多弯路也是有好处的,至少让我学到了很多以前没有接触到的属性.
每次找到一个错误,并解决的过程.就是一个学习的过程.这样会让你更深入的理解当前使用的技术.
不怕弯路多,就怕一帆风顺.一直没有弯路绕.
   
时间:2008-07-16
试试看设置p的line height css来解决你最早说的问题
   
0 请登录后投票
时间:2008-07-16
Quake Wang 写道
试试看设置p的line height css来解决你最早说的问题


试了一下您所说的方法.确实实现了将换行的高度变矮了.
可不知为什么.第一次在iframe中按回车的时候.之前所写的内容会自动的向上飘浮一段距离.
不知道该怎么控制.
   
0 请登录后投票
时间:2008-07-16
我前面忘记说了margin也要处理,这个问题在做richeditor时候都会遇到,通常是给iframe设置p的css style来解决,比如
p {
margin:0pt;
line-height: ...;
}
   
0 请登录后投票
时间:2008-07-16
Quake Wang 写道
我前面忘记说了margin也要处理,这个问题在做richeditor时候都会遇到,通常是给iframe设置p的css style来解决,比如
p {
margin:0pt;
line-height: ...;
}

...这下更惨.
直接使用margin:0pt;
不是向上飘.
而是许多行完全重叠在一起了...
设置margin-top:0pt;和之前效果一样.还是向上飘.
设置padding也一样.
   
0 请登录后投票
时间:2008-07-16
shift+enter不行吗?
   
0 请登录后投票
时间:2008-07-16
你还是给一个具体的例子吧,JavaEye的richeditor就是这样设置的,你可以在自己的博客界面用可视化编辑器发篇草稿试试看,用firebug查看一下样式表。
   
0 请登录后投票
时间:2008-07-16
achun 写道
shift+enter不行吗?

shift+enter确实是可以实现的.
不过一般聊天或写文章.有谁会无聊到+shift来进行换行?
   
0 请登录后投票
时间:2008-07-16
...
我晕了.白跑了那么多弯跑.
原来换行问题只要用
p{
margin:0px;
padding:0px;
}
就可以成功解决了.

强烈的BS自己.
发这个帖子简直就是误人子弟.

顺便感谢Quake Wang的提示.
   
0 请登录后投票
论坛首页 AJAX版 JavaScript

跳转论坛:
JavaEye推荐