富文本編輯器&FileReader

最近在作一個web版的管理Tool,其中包括一個編輯框,要求可以編輯文字,插入圖片,最後導出作成一個Html。對於資深人士看來,這很容易啊,不就是一個富文本編輯框嗎?這其實就是一個概念的問題,對有經驗的人來講,腦子裏面有了概念,就能一會兒抓到點上,快速地進行分析。可是對於我來講就沒有富文本編輯框的概念,加之因爲公司內有作網頁的比較少,可以求教的人很少,所以我只好一步一步慢慢研究,總之走了不少彎路。其中一些硌人的障礙就不說了。下面我就簡短地總結一下有關經驗吧。html


一.編輯框程序員

大多數富文本編輯框都是用iFrame作的。只要咱們將designMode屬性設置成"on",則個iframe就具有了編輯功能。web

先寫一個簡單的框架:chrome

複製代碼
<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的內容。app

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.獲取本地文本中的字符串

 

3、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>

如此一來,代碼的執行效率就提升了。

 

4、保存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 = "\n<body>" + iframeDocument.body.innerHTML + "</body>\n";
    var headHtml = "<head>" + iframeDocument.head.innerHTML + "</head>\n";
    var htmlFile = "<html>\n" + 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中的內容保存到本地了。

相關文章
相關標籤/搜索