• 富文本编辑器&FileReader


    最近在做一个web版的管理Tool,其中包括一个编辑框,要求能够编辑文字,插入图片,最后导出做成一个Html。对于资深人士看来,这很容易啊,不就是一个富文本编辑框吗?这其实就是一个概念的问题,对有经验的人来说,脑子里面有了概念,就能一下子抓到点上,快速地进行分析。但是对于我来说就没有富文本编辑框的概念,加之由于公司内有做网页的比较少,能够求教的人不多,因此我只好一步一步慢慢研究,总之走了很多弯路。其中一些硌人的障碍就不说了。下面我就简短地总结一下有关经验吧。


    一.编辑框

    大多数富文本编辑框都是用iFrame做的。只要我们将designMode属性设置成"on",则个iframe就具备了编辑功能。

    先写一个简单的框架:

    复制代码
    <html>
    <head>
    </head>
    <body>
        <textarea></textarea>
        <iframe id="iframe"></iframe>
      <sprint>
              createIframe:function(id){
                  $ = this= document.getElementById("id");
                  var doc =  $.contentDocument ||$.contentWindow.document; 
                  doc.designMode = 'on';
                  doc.open();
                  doc.write('<html><head><style>body{ margin:3px; word-wrap:break-word; word-break: break-all; }</style></head><body>GoodNessEditor</body></html>');
                  $.contentWindow.focus();
                  doc.close();
              }
          windown.onload = functon(){
                  refurn new createIframe("iframe");
              }
        </sprint>
    </body>
    </html>
    复制代码

     从上面代码我们可以得知,iframe的使用需要进行以下几个步骤:

    1.要获取iframe的document文档。

    var doc =  $.contentDocument ||$.contentWindow.document; 

    2.将文档设成设计模式。即:将designMode属性设置成"on"。

    3.打开文档(open),写入默认的document,关闭文档(close)。

      --当然也可以直接指定iframe的src来设定iframe的内容。

    ifram.src = "www.baidu.com";

    二.工具栏

    如果iframe是存放document的一个容器,那我会很好奇如何通过命令让容器里的document实现靠左、靠右、剪切、加粗、插入图片。这时就会用到execCommand命令。

    一般execCommand都带有一下三个参数:

    复制代码
    execCommand(String aCommandName, Boolean aShowDefaultUI, String aValueArgument)
    
    aCommandName  指令名称
    
    aShowDefaultUI    是否使用默认UI
    
    aValueArgument   具体命令(如是插入图片则输入url,如果插入文字则输入字符串)
    复制代码

        因为我这次所做的编辑器非常简单,只用到了图片插入以及插入文字。所以只使用到两种命令:

    图片插入
    execCommand("insertimage",falser,url);
    字符串插入
    execCommand("InsertInputText ",falser,text);

    知道这两种命令,接下来似乎就比较简单了。只要取到相应的图片URL以及要插入的字符串,就可以执行命令。

    但素,我是说但素,这两年程序员坐下来,我早已知道扣代码这种事,从来就没有能够让人省心的事。坑爹处处有啊你说是不是。

    在执行这两个命令之前,我们需要做两件事:

    1.获取本地图片URL

    2.获取本地文本中的字符串

    三、FileReader读取本地资源

    读取图片

    我也翻找过不少网上使用较多的富文本编辑器,在导入图片这一项上,基本都是使用网络资源,而不是只用本地资源。如果要使用本地资源,读取本地图片的URL,因此就涉及到Html5的FileReader。

    首先,我们需要使用fileupload来选择图片:

    复制代码
    <input type="file" onchange="fileSelect(this.files)" />
    
    <script>
        function fileSelect(files)(){
           var file = files[0],//因为可以选择多个文件,所以我们只需选取头一件即可
                 url;
    
           //判断文件是否存在
           if(file){
               if(file.tyoe.indexOf("image") < 0 ){
                    //判断是否为图片
                    alert("Please input image!");
                    return ;
               }
               if (window.webkitURL.createObjectURL) {
                //Chrome8+
                src = window.webkitURL.createObjectURL(file);
              } else{//IE8+
                  var reader = new FileReader();
                  reader.onload = function(){
                      url = e.target.result;
                  }
                 reader.readAsDataURL(file);
               }
           }
        }
    </script>
    复制代码

    上面我们用到了两种图片读取方法。

    一种是Html5原生的FileReader。但是这种方法是将图片读取成一个超长的二进制文件,如果图片过大,所生成的二进制文件也更大,对浏览器是一个承重的负担,因此不大建议使用。

    当然FileReader不只有一个方法,它有以下几个方法:

    readAsBinaryString(file)   将文件读取为二进制码
    
    readAsText(file,encode) 将文件读取为字符串
    
    readAsDataURL(file)        将文件读取为DataURL

    FileReader事件

    onabort              ---------数据读取中断时触发
    onerror              ---------数据读取出错时触发
    onloadstart          --------数据读取开始时触发
    onprocess            --------数据读取中
    onload               --------数据读取成功完成时触发
    onloadend            --------数据读取完成时触发,无论成功失败

    FileReader属性

    filereader.result        ---------读取结果
    
    filereader.readystate    ---------读取状态(empty loading down)

    另一种读取方法是Chrome和safari为代表的webkit浏览器所拥有的图片文件读取方式:window.webkitURL.createObjectURL(file).

     --通过这种方法,将得到一个已编码过的相对路径,相比而言,体积大大减少。

    读取到本地图片的URL后,我么就可以用execCommand指令将图片读入iframe中。

    复制代码
    <script>
        .......前略
        url = window.webkitURL.createObjectURL(file)
    var iframe = document.getElementById("iframe");
    var doc = iframe.contentDocument ||iframe.contentWindow.document;
    doc.execCommand("insertimage",false,url);
    iframe.contentWindow.focus(); </script>
    复制代码

    读取本地文本文件

    同样我们也可以用readerAsText来读取本地文件

    复制代码
    <script>
       function readText(files){
          var file = files[0];
          if (file) {
            
            var reader = new FileReader();
            var textResult;
    
            reader.onloadend = function (e) {
                textResult = e.target.result;
            }
            reader.readAsText(file, 'utf-8');
        }
       }
    
    </script>
    复制代码

    本地文本字符串后,就可以用execCommand指令将字符串读入iframe中..................

    <script>
     .....前略
        doc.execCommand("insertinputtext",false,text);
        doc.designMode = "off";
        iframe.contentWindow.focus();
    </script>

    如果你是这么想的,那你就太天真了!!!!!!!!!!!

    我测试了一下如果用execCommand("insertinputtext",false,text)指令,就可能回出现无法将读取的字符串插入iframe的情况,而且几率极高,插好多回都不一定能成功一次。后来想了一下,有可能是这个指令需要遍历iframe中所有的节点,然后再body的最后一个节点插入字符串。这就导致该指令的执行效率非常之低。很坑爹是不是!!!!所以与其遍历所有节点,不如直接将字符串插入想要的节点中去。于是我就用到了以下方法。

    <script>
      .......前略
      doc.getElementByTagName('body')[0].innerText = text;
    </script>

    如此一来,代码的执行效率就提高了。

    四、保存HTML文件

    这样一来,一个简单的富文本编辑器就算完成了,如果想增加其它功能,就请查找具体的execCommand命令。

    但是,我还想再增加一个特殊的功能,就是将iframe的document文件保存到本地。

    想当然的,肯定也会想到使用execCommand指令中的"saveAs"指令。

    但是很遗憾的告诉你,在一些比如chrome,FF上,saveAs指令是无效的。即便你使用它,也无法按照你的想象般弹出文件选择框出来。当然像IE之类的浏览器就不在我们的讨论范围之内了。

    我调查了一下为什么chrome无法使用saveAs指令的原因,是因为chrome为了提高浏览器的安全性,而禁止用JS将页面的文件保存到本地。

    那么,既然用不了浏览器自身的API,那就只好另寻它径了。我不能保存,但我总能下载吧。

    首先可以讲iframe的内容取出来。

    复制代码
    <script>
        var iframe = document.getElementById('RTE_iframe');
        var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
        var bodyHtml = "
    <body>" + iframeDocument.body.innerHTML + "</body>
    ";
        var headHtml = "<head>" + iframeDocument.head.innerHTML + "</head>
    ";
        var htmlFile = "<html>
    " + headHtml + bodyHtml + "</html>";
    </script>
    复制代码

    之后就是要将这些东西下载到本地。

    复制代码
    <script>
      var BlobBuilder = BlobBuilder || WebKitBlobBuilder || MozBlobBuilder;
      var URL = URL || webkitURL || window;
      function saveAs(blob, filename) {
            var type = blob.type;
            var force_saveable_type = 'application/octet-stream';
            if (type && type != force_saveable_type) { // 强制下载,而非在浏览器中打开
                var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
                blob = slice.call(blob, 0, blob.size, force_saveable_type);
            }
    
            var url = URL.createObjectURL(blob);
            var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
            save_link.href = url;
            save_link.download = filename;
    
            var event = document.createEvent('MouseEvents');
            event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            save_link.dispatchEvent(event);
            URL.revokeObjectURL(url);
        }
    
        var bb = new BlobBuilder;
        bb.append(htmlFile);
        saveAs(bb.getBlob('text/plain;charset=utf-8'), "test.html");
    </script>
    复制代码

    这样,就能够将iframe中的内容保存到本地了。

  • 相关阅读:
    JS・TextArea 字符串长度限制
    JavaScript面试题目集锦
    IE内存泄露分析
    JS动态添加样式和脚本
    取消锚(<a/>)点击后页面跳转的几种方法
    JS代码片段整理
    IE缓存问题的解决方法
    字符串与数字 转换
    如何安装和配置Cassandra
    字类和超类的转化问题
  • 原文地址:https://www.cnblogs.com/chris-oil/p/3454158.html
Copyright © 2020-2023  润新知