• 将HTML导出生成word文档


    前言:

    项目开发中遇到了需要将HTML页面的内容导出为一个word文档,所以有了这边随笔。

    当然,项目开发又时间有点紧迫,第一时间想到的是用插件,所以百度了下。下面就介绍两个导出word文档的方法。

    法一:通过jquery.wordexport.js导出word

    备注:兼容IE9以上

    大概浏览了下jquery.wordexport.js插件的代码,了解到了通过该插件可以导出文本和图片,而图片首先通过canvas的形式

    绘制,文本则需要再依赖FileSaver.js插件,FileSaver.js插件则主要通过H5的文件操作新特性new Blob()和new FileReader()

    来实现文本的导出。

    插件源码:

    FileSaver.js

      1 /* FileSaver.js
      2  * A saveAs() FileSaver implementation.
      3  * 1.3.2
      4  * 2016-06-16 18:25:19
      5  *
      6  * By Eli Grey, http://eligrey.com
      7  * License: MIT
      8  *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
      9  */
     10 
     11 /*global self */
     12 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
     13 
     14 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
     15 
     16 var saveAs = saveAs || (function(view) {
     17         "use strict";
     18         // IE <10 is explicitly unsupported
     19         if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]./.test(navigator.userAgent)) {
     20             return;
     21         }
     22         var
     23             doc = view.document
     24         // only get URL when necessary in case Blob.js hasn't overridden it yet
     25             , get_URL = function() {
     26                 return view.URL || view.webkitURL || view;
     27             }
     28             , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
     29             , can_use_save_link = "download" in save_link
     30             , click = function(node) {
     31                 var event = new MouseEvent("click");
     32                 node.dispatchEvent(event);
     33             }
     34             , is_safari = /constructor/i.test(view.HTMLElement)
     35             , is_chrome_ios =/CriOS/[d]+/.test(navigator.userAgent)
     36             , throw_outside = function(ex) {
     37                 (view.setImmediate || view.setTimeout)(function() {
     38                     throw ex;
     39                 }, 0);
     40             }
     41             , force_saveable_type = "application/octet-stream"
     42         // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
     43             , arbitrary_revoke_timeout = 1000 * 40 // in ms
     44             , revoke = function(file) {
     45                 var revoker = function() {
     46                     if (typeof file === "string") { // file is an object URL
     47                         get_URL().revokeObjectURL(file);
     48                     } else { // file is a File
     49                         file.remove();
     50                     }
     51                 };
     52                 setTimeout(revoker, arbitrary_revoke_timeout);
     53             }
     54             , dispatch = function(filesaver, event_types, event) {
     55                 event_types = [].concat(event_types);
     56                 var i = event_types.length;
     57                 while (i--) {
     58                     var listener = filesaver["on" + event_types[i]];
     59                     if (typeof listener === "function") {
     60                         try {
     61                             listener.call(filesaver, event || filesaver);
     62                         } catch (ex) {
     63                             throw_outside(ex);
     64                         }
     65                     }
     66                 }
     67             }
     68             , auto_bom = function(blob) {
     69                 // prepend BOM for UTF-8 XML and text/* types (including HTML)
     70                 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
     71                 if (/^s*(?:text/S*|application/xml|S*/S*+xml)s*;.*charsets*=s*utf-8/i.test(blob.type)) {
     72                     return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
     73                 }
     74                 return blob;
     75             }
     76             , FileSaver = function(blob, name, no_auto_bom) {
     77                 if (!no_auto_bom) {
     78                     blob = auto_bom(blob);
     79                 }
     80                 // First try a.download, then web filesystem, then object URLs
     81                 var
     82                     filesaver = this
     83                     , type = blob.type
     84                     , force = type === force_saveable_type
     85                     , object_url
     86                     , dispatch_all = function() {
     87                         dispatch(filesaver, "writestart progress write writeend".split(" "));
     88                     }
     89                 // on any filesys errors revert to saving with object URLs
     90                     , fs_error = function() {
     91                         if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
     92                             // Safari doesn't allow downloading of blob urls
     93                             var reader = new FileReader();
     94                             reader.onloadend = function() {
     95                                 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
     96                                 var popup = view.open(url, '_blank');
     97                                 if(!popup) view.location.href = url;
     98                                 url=undefined; // release reference before dispatching
     99                                 filesaver.readyState = filesaver.DONE;
    100                                 dispatch_all();
    101                             };
    102                             reader.readAsDataURL(blob);
    103                             filesaver.readyState = filesaver.INIT;
    104                             return;
    105                         }
    106                         // don't create more object URLs than needed
    107                         if (!object_url) {
    108                             object_url = get_URL().createObjectURL(blob);
    109                         }
    110                         if (force) {
    111                             view.location.href = object_url;
    112                         } else {
    113                             var opened = view.open(object_url, "_blank");
    114                             if (!opened) {
    115                                 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
    116                                 view.location.href = object_url;
    117                             }
    118                         }
    119                         filesaver.readyState = filesaver.DONE;
    120                         dispatch_all();
    121                         revoke(object_url);
    122                     }
    123                     ;
    124                 filesaver.readyState = filesaver.INIT;
    125 
    126                 if (can_use_save_link) {
    127                     object_url = get_URL().createObjectURL(blob);
    128                     setTimeout(function() {
    129                         save_link.href = object_url;
    130                         save_link.download = name;
    131                         click(save_link);
    132                         dispatch_all();
    133                         revoke(object_url);
    134                         filesaver.readyState = filesaver.DONE;
    135                     });
    136                     return;
    137                 }
    138 
    139                 fs_error();
    140             }
    141             , FS_proto = FileSaver.prototype
    142             , saveAs = function(blob, name, no_auto_bom) {
    143                 return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
    144             }
    145             ;
    146         // IE 10+ (native saveAs)
    147         if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
    148             return function(blob, name, no_auto_bom) {
    149                 name = name || blob.name || "download";
    150 
    151                 if (!no_auto_bom) {
    152                     blob = auto_bom(blob);
    153                 }
    154                 return navigator.msSaveOrOpenBlob(blob, name);
    155             };
    156         }
    157 
    158         FS_proto.abort = function(){};
    159         FS_proto.readyState = FS_proto.INIT = 0;
    160         FS_proto.WRITING = 1;
    161         FS_proto.DONE = 2;
    162 
    163         FS_proto.error =
    164             FS_proto.onwritestart =
    165                 FS_proto.onprogress =
    166                     FS_proto.onwrite =
    167                         FS_proto.onabort =
    168                             FS_proto.onerror =
    169                                 FS_proto.onwriteend =
    170                                     null;
    171 
    172         return saveAs;
    173     }(
    174         typeof self !== "undefined" && self
    175         || typeof window !== "undefined" && window
    176         || this.content
    177     ));
    178 // `self` is undefined in Firefox for Android content script context
    179 // while `this` is nsIContentFrameMessageManager
    180 // with an attribute `content` that corresponds to the window
    181 
    182 if (typeof module !== "undefined" && module.exports) {
    183     module.exports.saveAs = saveAs;
    184 } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
    185     define([], function() {
    186         return saveAs;
    187     });
    188 }
    View Code

    jquery.wordexport.js

     1 if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
     2     (function($) {
     3         $.fn.wordExport = function(fileName) {
     4             fileName = typeof fileName !== 'undefined' ? fileName : "jQuery-Word-Export";
     5             var static = {
     6                 mhtml: {
     7                     top: "Mime-Version: 1.0
    Content-Base: " + location.href + "
    Content-Type: Multipart/related; boundary="NEXT.ITEM-BOUNDARY";type="text/html"
    
    --NEXT.ITEM-BOUNDARY
    Content-Type: text/html; charset="utf-8"
    Content-Location: " + location.href + "
    
    <!DOCTYPE html>
    <html>
    _html_</html>",
     8                     head: "<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <style>
    _styles_
    </style>
    </head>
    ",
     9                     body: "<body>_body_</body>"
    10                 }
    11             };
    12             var options = {
    13                 maxWidth: 624
    14             };
    15             // Clone selected element before manipulating it
    16             var markup = $(this).clone();
    17 
    18             // Remove hidden elements from the output
    19             markup.each(function() {
    20                 var self = $(this);
    21                 if (self.is(':hidden'))
    22                     self.remove();
    23             });
    24 
    25             // Embed all images using Data URLs
    26             var images = Array();
    27             var img = markup.find('img');
    28             for (var i = 0; i < img.length; i++) {
    29                 // Calculate dimensions of output image
    30                 var w = Math.min(img[i].width, options.maxWidth);
    31                 var h = img[i].height * (w / img[i].width);
    32                 // Create canvas for converting image to data URL
    33                 var canvas = document.createElement("CANVAS");
    34                 canvas.width = w;
    35                 canvas.height = h;
    36                 // Draw image to canvas
    37                 var context = canvas.getContext('2d');
    38                 context.drawImage(img[i], 0, 0, w, h);
    39                 // Get data URL encoding of image
    40                 var uri = canvas.toDataURL("image/png/jpg");
    41                 $(img[i]).attr("src", img[i].src);
    42                 img[i].width = w;
    43                 img[i].height = h;
    44                 // Save encoded image to array
    45                 images[i] = {
    46                     type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
    47                     encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
    48                     location: $(img[i]).attr("src"),
    49                     data: uri.substring(uri.indexOf(",") + 1)
    50                 };
    51             }
    52 
    53             // Prepare bottom of mhtml file with image data
    54             var mhtmlBottom = "
    ";
    55             for (var i = 0; i < images.length; i++) {
    56                 mhtmlBottom += "--NEXT.ITEM-BOUNDARY
    ";
    57                 mhtmlBottom += "Content-Location: " + images[i].location + "
    ";
    58                 mhtmlBottom += "Content-Type: " + images[i].type + "
    ";
    59                 mhtmlBottom += "Content-Transfer-Encoding: " + images[i].encoding + "
    
    ";
    60                 mhtmlBottom += images[i].data + "
    
    ";
    61             }
    62             mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";
    63 
    64             //TODO: load css from included stylesheet
    65 
    66             //var styles=' /* Font Definitions */@font-face{font-family:宋体;panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-alt:SimSun;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;}  @font-face{font-family:"Cambria Math";panose-1:2 4 5 3 5 4 6 3 2 4;mso-font-charset:1;mso-generic-font-family:roman;mso-font-format:other;mso-font-pitch:variable;mso-font-signature:0 0 0 0 0 0;}  @font-face{font-family:"@宋体";panose-1:2 1 6 0 3 1 1 1 1 1;mso-font-charset:134;mso-generic-font-family:auto;mso-font-pitch:variable;mso-font-signature:3 680460288 22 0 262145 0;}/* Style Definitions */p.MsoNormal, li.MsoNormal, div.MsoNormal{mso-style-unhide:no;mso-style-qformat:yes;mso-style-parent:"";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;font-size:14.0pt;font-family:宋体;mso-bidi-font-family:宋体;}p.MsoHeader, li.MsoHeader, div.MsoHeader{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"页眉 Char";margin:0cm;margin-bottom:.0001pt;text-align:center;mso-pagination:widow-orphan;layout-grid-mode:char;font-size:9.0pt;font-family:宋体;mso-bidi-font-family:宋体;}p.MsoFooter, li.MsoFooter, div.MsoFooter{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"页脚 Char";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;layout-grid-mode:char;font-size:9.0pt;font-family:宋体;mso-bidi-font-family:宋体;}p.MsoAcetate, li.MsoAcetate, div.MsoAcetate{mso-style-noshow:yes;mso-style-priority:99;mso-style-link:"批注框文本 Char";margin:0cm;margin-bottom:.0001pt;mso-pagination:widow-orphan;font-size:9.0pt;font-family:宋体;mso-bidi-font-family:宋体;}span.Char{mso-style-name:"页眉 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:页眉;font-family:宋体;mso-ascii-font-family:宋体;mso-fareast-font-family:宋体;mso-hansi-font-family:宋体;}span.Char0{mso-style-name:"页脚 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:页脚;font-family:宋体;mso-ascii-font-family:宋体;mso-fareast-font-family:宋体;mso-hansi-font-family:宋体;}span.Char1{mso-style-name:"批注框文本 Char";mso-style-noshow:yes;mso-style-priority:99;mso-style-unhide:no;mso-style-locked:yes;mso-style-link:批注框文本;font-family:宋体;mso-ascii-font-family:宋体;mso-fareast-font-family:宋体;mso-hansi-font-family:宋体;}p.msochpdefault, li.msochpdefault, div.msochpdefault{mso-style-name:msochpdefault;mso-style-unhide:no;mso-margin-top-alt:auto;margin-right:0cm;mso-margin-bottom-alt:auto;margin-left:0cm;mso-pagination:widow-orphan;font-size:10.0pt;font-family:宋体;mso-bidi-font-family:宋体;}span.msonormal0{mso-style-name:msonormal;mso-style-unhide:no;}.MsoChpDefault{mso-style-type:export-only;mso-default-props:yes;font-size:10.0pt;mso-ansi-font-size:10.0pt;mso-bidi-font-size:10.0pt;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman";mso-font-kerning:0pt;}/* Page Definitions */  @page WordSection1{size:595.3pt 841.9pt;margin:72.0pt 90.0pt 72.0pt 90.0pt;mso-header-margin:42.55pt;mso-footer-margin:49.6pt;mso-paper-source:0;}div.WordSection1{page:WordSection1;}';
    67 
    68             var styles="";
    69 
    70             // Aggregate parts of the file together
    71             var fileContent = static.mhtml.top.replace("_html_", static.mhtml.head.replace("_styles_", styles) + static.mhtml.body.replace("_body_", markup.html())) + mhtmlBottom;
    72 
    73             // Create a Blob with the file contents
    74             var blob = new Blob([fileContent], {
    75                 type: "application/msword;charset=utf-8"
    76             });
    77             saveAs(blob, fileName + ".doc");
    78         };
    79     })(jQuery);
    80 } else {
    81     if (typeof jQuery === "undefined") {
    82         console.error("jQuery Word Export: missing dependency (jQuery)");
    83     }
    84     if (typeof saveAs === "undefined") {
    85         console.error("jQuery Word Export: missing dependency (FileSaver.js)");
    86     }
    87 }
    View Code

    插件调用:

     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title>生成word文档</title>
     6 </head>
     7 <body lang=ZH-CN style='tab-interval:21.0pt'>
     8 <div class="word">
     9     <p align="center" style="font-size:20pt;font-weight:bold;">JS导出Word文档</p>
    10 </div>
    11 <input type="button" value="导出word">
    12 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
    13 <script type="text/javascript" src="js/FileSaver.js"></script>
    14 <script type="text/javascript" src="js/jquery.wordexport.js"></script>
    15 <script>
    16     $(function(){
    17         $("input[type='button']").click(function(event) {
    18             $(".word").wordExport('生成word文档');
    19         });
    20     })
    21 </script>
    22 </body>
    23 </html>

    直接调用wordExport()接口就可以导出word文档,传的参数为导出的word文件名。

    补充:

    通过我们常规写的外联样式设置样式是无效的,通过个人的实践发现需要写内联样式才能生效,而单位也需要按照word的配置

    单位pt设置。

    而jquery.wordexport.js插件是要配置了个style样式让我们补充样式设置的:

    但是个人实践了下,设置的样式却无法生效,只能通过内联设置才生效。

    截图:

    法二:通过百度js模板引擎生成word文档

    主要是通过js模板设置对应的标签,然后XDoc.to(baidu.template())导出word,而通过百度js模板引擎的好处是也可以导出PDF文件。

    完整demo:

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <meta charset="UTF-8">
     5     <script type="text/javascript" src="http://www.xdocin.com/xdoc.js"></script>
     6     <script type="text/javascript" src="http://www.xdocin.com/baiduTemplate.js"></script>
     7     <style>
     8         .head{
     9             font-size: 29px;
    10             display: block;
    11         }
    12         .content{
    13             display: block;
    14         }
    15     </style>
    16 </head>
    17 <body>
    18 <input type="button" onclick="gen('pdf')" value="生成PDF"/>
    19 <input type="button" onclick="gen('docx')" value="生成Word"/>
    20 <br/>
    21 <script id="tmpl" type="text/html">
    22     <xdoc version="A.3.0">
    23         <body>
    24         <para heading="1" lineSpacing="28">
    25             <text class="head" valign="center" fontName="标宋" fontSize="29"><%=title%></text>
    26         </para>
    27         <para>
    28             <img  src="<%=img%>" sizeType="autosize"/>
    29         </para>
    30         <para lineSpacing="9">
    31             <text class="content" fontName="仿宋" fontSize="18"><%=content%></text>
    32         </para>
    33         </body>
    34     </xdoc>
    35 </script>
    36 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
    37 <script type="text/javascript">
    38     var type="docx";//pdf
    39     var data = {
    40         title: "导出"+type+"文件",
    41         img: "http://www.wordlm.com/uploads/allimg/130101/1_130101000405_1.jpg",
    42         content: "我这样就可以导出"+type+"格式的文件了,是不是很方便",
    43     };
    44     function renderTemplate(){
    45         var template=$("#tmpl").html();
    46         var html=template.replace(/<%=title%>/,data.title)
    47                 .replace(/<%=img%>/,data.img)
    48                 .replace(/<%=content%>/,data.content);
    49         $("body").append(html);
    50     }
    51     renderTemplate();
    52     function gen(type) {
    53         XDoc.to(baidu.template('tmpl', data), type, {}, "_blank");
    54     }
    55     console.log('http://www.xdocin.com/xml.html');
    56 </script>
    57 </body>
    58 </html>  

    这里我通过renderTemplate函数叫js模板渲染到HTML中,实现了文本的展示和导出内容的结合。而因为这里导出的word文档是需要特别设置样式的,所以在页面样式展示下我们可以通过添加.class的方式设置。

    附部分导出word文档样式设置:

    截图:

    更多参考:

    FileSave.js:https://github.com/eligrey/FileSaver.js

    百度导出文档模板:http://www.xdocin.com/xml.html

  • 相关阅读:
    bootstrap-table 数据表格行内修改
    java文件上传(单文件 多文件)与删除
    bootstrap-table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)
    bootstrap-table 大量字段整体表单上传之时间处理
    Java实习问题记录
    Playbook剧本初识
    自动化运维工具-Ansible基础
    性能优化概述
    Rewrite基本概述
    Nginx常见问题
  • 原文地址:https://www.cnblogs.com/aaron-pan/p/7132059.html
Copyright © 2020-2023  润新知