【HTML5版】導出Table數據並保存爲Excel

首發個人博客 http://blog.meathill.com/tech/js/export-table-data-into-a-excel-file.htmlhtml

最近接到這麼個需求,要把<table>顯示的數據導出成Excel表。相似的需求並不稀罕,過去我一般用PHP輸出.csv文件,不過此次彷佛不能這麼作:數據源表格容許用戶篩選和排序,與原始數據表有區別,而傳遞操做又比較麻煩;另外.csv文件的功能受限嚴重,難以擴展。因此我準備嘗試下別的作法。web

Google之,發現HTML5又成了一座分水嶺。以前在IE瀏覽器下,用戶能夠利用ActiveXObject建立Excel.application對象來處理——固然不兼容Mac。後來Excel開放標準,能夠導出xml格式的文件,dataURI就有了用武之地,導出<table>數據並保存爲Excel有了更好的選擇。瀏覽器

(如下內容與StackOverflow中的答案有重合,那個3條贊同的我認爲是最佳答案,惋惜我無法頂他……)app

準備工做

  1. 建立一個空白的Excel文檔
  2. 另存爲「XML表格」,xml格式
  3. 好了,模版搞定

圖省事兒的也能夠直接使用個人模板(這一段我使用了Handlebars,以便未來填充數據)dom

template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">\
  <head><!--[if gte mso 9]>\
    <xml>\
      <x:ExcelWorkbook>\
        <x:ExcelWorksheets>\
          <x:ExcelWorksheet>\
            <x:Name>{{worksheet}}</x:Name>\
            <x:WorksheetOptions>\
              <x:DisplayGridlines/>\
            </x:WorksheetOptions>\
          </x:ExcelWorksheet>\
        </x:ExcelWorksheets>\
      </x:ExcelWorkbook>\
    </xml><![endif]-->\
  </head>\
  <body>\
    {{#each tables}}<table>{{{this}}}</table>{{/each}}\
  </body>\
</html>';

複製表格數據

複製數據比較簡單了。如前面模版所示,這裏我很野蠻的直接複製theadtbody的所有代碼,填充內容。固然爲了體現用戶操做,我只複製顯示的tr。這裏須要注意的是,jQuery判斷一個dom是否處於顯示狀體基於如下3點:函數

  1. display:none
  2. 表單元素,type="hidden"
  3. 寬高爲0
  4. 父級以上節點不顯示,本身也不會顯示

因此,不能先clone()find(':hidden').remove(),由於沒添加到主Dom樹的節點寬高都是0,也就會被認爲還沒顯示,這下就都幹掉了。this

輸出內容

套用模版以後,咱們就有了完整的表格數據。接下來,咱們須要把其轉換成base64格式,以便套用dataURI輸出。因而便要使用btoa這個函數(將二進制數據轉換成base64格式的字符串,HTML5的大禮之一,操做二進制的API),不過注意,這個函數不能直接轉換普通unicode字符,否則大多數瀏覽器都會拋出異常。因此須要先通過兩步轉換:excel

function base64(string) {
  return window.btoa(unescape(encodeURIComponent(string)));
}

(MDN中還推薦了另一種作法,經過Typed Array作中介,我沒有實操,有興趣的能夠試下)code

而後配上base64頭和mime類型,就能夠觸發下載了:xml

var uri = 'data:application/vnd.ms-excel;base64,';
location.href = uri + base64(template(tables));

提高體驗

貌似到這裏就完成了,不過做爲一名掛職產品總監的碼農,我很難容忍下載的文件文件名是「下載」,並且尚未擴展名(Windows 8下沒有;Windows 7 和 Mac下會有.xls的擴展名,我認爲和已裝軟件註冊過的mime類型有關)。

這是個用在內部管理後臺的需求,我以前曾要求你們必須使用Chrome訪問後臺;並且我知道,Chrome已經支持<a>裏的download屬性。那麼這就好辦了,由於onclick事件會先於系統默認行爲觸發,因此我能夠在這個事件的處理函數中將生成的Base64放在被點擊按鈕的href裏,並將其download屬性設爲容易理解的「某年某月末日至某年某月某日廣告數據分析.xls」。至此,此項功能宣告圓滿。

HTML部分(使用到Bootstrap和Handlebars):

<a href="#" title="點擊下載" class="btn btn-primary export-button" download="{{start}}至{{end}}廣告數據分析.xls"><i class="icon-download-alt icon-white"></i> 導出</a>

JavaScript部分

tableToExcel: function (tableList, name) {
  var tables = [],
      uri = 'data:application/vnd.ms-excel;base64,',
      template = Handlebars.compile('<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{{worksheet}}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>{{#each tables}}<table>{{{this}}}</table>{{/each}}</body></html>');

  for (var i = 0; i < tableList.length; i++) {
    tables.push(tableList[i].innerHTML);
  }
  var data = {
    worksheet: name || 'Worksheet',
    tables: tables
  };
  return uri + base64(template(data));
},
exportHandler: function (event) {
  var tables = this.$('table'),
      table = null;
  tables.each(function (i) {
    var t = $('<table><thead></thead><tbody></tobdy></table>');
    t.find('thead').html(this.tHead.innerHTML);
    t.find('tbody').append($(this.tBodies).children(':visible').clone());
    t.find('.not-print').remove(); // not-print 是@media print中不會打印的部分
    t.find('a').replaceWith(function (i) { // 表格中再也不須要的超連接也移除了
      return this.innerHTML;
    });
    table = table ? table.add(t) : t;
  });
  event.currentTarget.href = Dianjoy.utils.tableToExcel(table, '廣告數據');
}

尾聲

說是圓滿,其實也不盡然,由於URL有2M的長度限制,遇到真正的大表仍然可能出問題(我沒實測)。

最後例行吐槽:老闆(領導)想提高工做效率,光逼員工沒啥意義,必須關注員工平常使用的軟件:不準用亂七八糟的瀏覽器,統一Chrome;360一率禁用(最近遇到N起升級Chrome Dev 30版致使各類bug的問題);所有裝Windows 8(自帶殺毒,幾乎全部外設秒配)。能作到這幾點,公司辦公效率提高1倍不止。

再多說兩句:咱們對外的後臺雖然作到了基本兼容,但若是用戶使用非Chrome訪問,仍然會建議他換用Chrome。目前Chrome訪問佔比已經上升到90%,IE678不到5%,但願不久的未來,咱們的用戶都能盡情享受HTML5帶來的優秀體驗,咱們的開發成本也能降得更低。

相關文章
相關標籤/搜索