前言:

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

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

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

备注:兼容IE9以上

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

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

来实现文本的导出。

插件源码:

FileSaver.js

 /* FileSaver.js
  * A saveAs() FileSaver implementation.
  * 1.3.2
  * 2016-06-16 18:25:19
  *
  * By Eli Grey, http://eligrey.com
  * License: MIT
  *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
  */

 /*global self */
 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */

 var saveAs = saveAs || (function(view) {
         "use strict";
         // IE <10 is explicitly unsupported
         -]\./.test(navigator.userAgent)) {
             return;
         }
         var
             doc = view.document
         // only get URL when necessary in case Blob.js hasn't overridden it yet
             , get_URL = function() {
                 return view.URL || view.webkitURL || view;
             }
             , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
             , can_use_save_link = "download" in save_link
             , click = function(node) {
                 var event = new MouseEvent("click");
                 node.dispatchEvent(event);
             }
             , is_safari = /constructor/i.test(view.HTMLElement)
             , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
             , throw_outside = function(ex) {
                 (view.setImmediate || view.setTimeout)(function() {
                     throw ex;
                 }, );
             }
             , force_saveable_type = "application/octet-stream"
         // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
             , arbitrary_revoke_timeout =  *  // in ms
             , revoke = function(file) {
                 var revoker = function() {
                     if (typeof file === "string") { // file is an object URL
                         get_URL().revokeObjectURL(file);
                     } else { // file is a File
                         file.remove();
                     }
                 };
                 setTimeout(revoker, arbitrary_revoke_timeout);
             }
             , dispatch = function(filesaver, event_types, event) {
                 event_types = [].concat(event_types);
                 var i = event_types.length;
                 while (i--) {
                     var listener = filesaver["on" + event_types[i]];
                     if (typeof listener === "function") {
                         try {
                             listener.call(filesaver, event || filesaver);
                         } catch (ex) {
                             throw_outside(ex);
                         }
                     }
                 }
             }
             , auto_bom = function(blob) {
                 // prepend BOM for UTF-8 XML and text/* types (including HTML)
                 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
                 /i.test(blob.type)) {
                     return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
                 }
                 return blob;
             }
             , FileSaver = function(blob, name, no_auto_bom) {
                 if (!no_auto_bom) {
                     blob = auto_bom(blob);
                 }
                 // First try a.download, then web filesystem, then object URLs
                 var
                     filesaver = this
                     , type = blob.type
                     , force = type === force_saveable_type
                     , object_url
                     , dispatch_all = function() {
                         dispatch(filesaver, "writestart progress write writeend".split(" "));
                     }
                 // on any filesys errors revert to saving with object URLs
                     , fs_error = function() {
                         if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
                             // Safari doesn't allow downloading of blob urls
                             var reader = new FileReader();
                             reader.onloadend = function() {
                                 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
                                 var popup = view.open(url, '_blank');
                                 if(!popup) view.location.href = url;
                                 url=undefined; // release reference before dispatching
                                 filesaver.readyState = filesaver.DONE;
                                 dispatch_all();
                             };
                             reader.readAsDataURL(blob);
                             filesaver.readyState = filesaver.INIT;
                             return;
                         }
                         // don't create more object URLs than needed
                         if (!object_url) {
                             object_url = get_URL().createObjectURL(blob);
                         }
                         if (force) {
                             view.location.href = object_url;
                         } else {
                             var opened = view.open(object_url, "_blank");
                             if (!opened) {
                                 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
                                 view.location.href = object_url;
                             }
                         }
                         filesaver.readyState = filesaver.DONE;
                         dispatch_all();
                         revoke(object_url);
                     }
                     ;
                 filesaver.readyState = filesaver.INIT;

                 if (can_use_save_link) {
                     object_url = get_URL().createObjectURL(blob);
                     setTimeout(function() {
                         save_link.href = object_url;
                         save_link.download = name;
                         click(save_link);
                         dispatch_all();
                         revoke(object_url);
                         filesaver.readyState = filesaver.DONE;
                     });
                     return;
                 }

                 fs_error();
             }
             , FS_proto = FileSaver.prototype
             , saveAs = function(blob, name, no_auto_bom) {
                 return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
             }
             ;
         // IE 10+ (native saveAs)
         if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
             return function(blob, name, no_auto_bom) {
                 name = name || blob.name || "download";

                 if (!no_auto_bom) {
                     blob = auto_bom(blob);
                 }
                 return navigator.msSaveOrOpenBlob(blob, name);
             };
         }

         FS_proto.abort = function(){};
         FS_proto.readyState = FS_proto.INIT = ;
         FS_proto.WRITING = ;
         FS_proto.DONE = ;

         FS_proto.error =
             FS_proto.onwritestart =
                 FS_proto.onprogress =
                     FS_proto.onwrite =
                         FS_proto.onabort =
                             FS_proto.onerror =
                                 FS_proto.onwriteend =
                                     null;

         return saveAs;
     }(
         typeof self !== "undefined" && self
         || typeof window !== "undefined" && window
         || this.content
     ));
 // `self` is undefined in Firefox for Android content script context
 // while `this` is nsIContentFrameMessageManager
 // with an attribute `content` that corresponds to the window

 if (typeof module !== "undefined" && module.exports) {
     module.exports.saveAs = saveAs;
 } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
     define([], function() {
         return saveAs;
     });
 }

jquery.wordexport.js

 if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
     (function($) {
         $.fn.wordExport = function(fileName) {
             fileName = typeof fileName !== 'undefined' ? fileName : "jQuery-Word-Export";
             var static = {
                 mhtml: {
                     top: "Mime-Version: 1.0\nContent-Base: " + location.href + "\nContent-Type: Multipart/related; boundary=\"NEXT.ITEM-BOUNDARY\";type=\"text/html\"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset=\"utf-8\"\nContent-Location: " + location.href + "\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
                     head: "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<style>\n_styles_\n</style>\n</head>\n",
                     body: "<body>_body_</body>"
                 }
             };
             var options = {
                 maxWidth:
             };
             // Clone selected element before manipulating it
             var markup = $(this).clone();

             // Remove hidden elements from the output
             markup.each(function() {
                 var self = $(this);
                 if (self.is(':hidden'))
                     self.remove();
             });

             // Embed all images using Data URLs
             var images = Array();
             var img = markup.find('img');
             ; i < img.length; i++) {
                 // Calculate dimensions of output image
                 var w = Math.min(img[i].width, options.maxWidth);
                 var h = img[i].height * (w / img[i].width);
                 // Create canvas for converting image to data URL
                 var canvas = document.createElement("CANVAS");
                 canvas.width = w;
                 canvas.height = h;
                 // Draw image to canvas
                 var context = canvas.getContext('2d');
                 context.drawImage(img[i], , , w, h);
                 // Get data URL encoding of image
                 var uri = canvas.toDataURL("image/png/jpg");
                 $(img[i]).attr("src", img[i].src);
                 img[i].width = w;
                 img[i].height = h;
                 // Save encoded image to array
                 images[i] = {
                     type: uri.substring(uri.indexOf(, uri.indexOf(";")),
                     encoding: uri.substring(uri.indexOf(, uri.indexOf(",")),
                     location: $(img[i]).attr("src"),
                     data: uri.substring(uri.indexOf()
                 };
             }

             // Prepare bottom of mhtml file with image data
             var mhtmlBottom = "\n";
             ; i < images.length; i++) {
                 mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
                 mhtmlBottom += "Content-Location: " + images[i].location + "\n";
                 mhtmlBottom += "Content-Type: " + images[i].type + "\n";
                 mhtmlBottom += "Content-Transfer-Encoding: " + images[i].encoding + "\n\n";
                 mhtmlBottom += images[i].data + "\n\n";
             }
             mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";

             //TODO: load css from included stylesheet

             //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;}';

             var styles="";

             // Aggregate parts of the file together
             var fileContent = static.mhtml.top.replace("_html_", static.mhtml.head.replace("_styles_", styles) + static.mhtml.body.replace("_body_", markup.html())) + mhtmlBottom;

             // Create a Blob with the file contents
             var blob = new Blob([fileContent], {
                 type: "application/msword;charset=utf-8"
             });
             saveAs(blob, fileName + ".doc");
         };
     })(jQuery);
 } else {
     if (typeof jQuery === "undefined") {
         console.error("jQuery Word Export: missing dependency (jQuery)");
     }
     if (typeof saveAs === "undefined") {
         console.error("jQuery Word Export: missing dependency (FileSaver.js)");
     }
 }

插件调用:

 <!DOCTYPE html>
 <html>
 <head lang="en">
     <meta charset="UTF-8">
     <title>生成word文档</title>
 </head>
 <body lang=ZH-CN style='tab-interval:21.0pt'>
 <div class="word">
     <p align="center" style="font-size:20pt;font-weight:bold;">JS导出Word文档</p>
 </div>
 <input type="button" value="导出word">
 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
 <script type="text/javascript" src="js/FileSaver.js"></script>
 <script type="text/javascript" src="js/jquery.wordexport.js"></script>
 <script>
     $(function(){
         $("input[type='button']").click(function(event) {
             $(".word").wordExport('生成word文档');
         });
     })
 </script>
 </body>
 </html>

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

补充:

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

单位pt设置。

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

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

截图:

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

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

完整demo:

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="UTF-8">
     <script type="text/javascript" src="http://www.xdocin.com/xdoc.js"></script>
     <script type="text/javascript" src="http://www.xdocin.com/baiduTemplate.js"></script>
     <style>
         .head{
             font-size: 29px;
             display: block;
         }
         .content{
             display: block;
         }
     </style>
 </head>
 <body>
 <input type="button" onclick="gen('pdf')" value="生成PDF"/>
 <input type="button" onclick="gen('docx')" value="生成Word"/>
 <br/>
 <script id="tmpl" type="text/html">
     <xdoc version="A.3.0">
         <body>
         <para heading="1" lineSpacing="28">
             <text class="head" valign="center" fontName="标宋" fontSize="29"><%=title%></text>
         </para>
         <para>
             <img  src="<%=img%>" sizeType="autosize"/>
         </para>
         <para lineSpacing="9">
             <text class="content" fontName="仿宋" fontSize="18"><%=content%></text>
         </para>
         </body>
     </xdoc>
 </script>
 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
 <script type="text/javascript">
     var type="docx";//pdf
     var data = {
         title: "导出"+type+"文件",
         img: "http://www.wordlm.com/uploads/allimg/130101/1_130101000405_1.jpg",
         content: "我这样就可以导出"+type+"格式的文件了,是不是很方便",
     };
     function renderTemplate(){
         var template=$("#tmpl").html();
         var html=template.replace(/<%=title%>/,data.title)
                 .replace(/<%=img%>/,data.img)
                 .replace(/<%=content%>/,data.content);
         $("body").append(html);
     }
     renderTemplate();
     function gen(type) {
         XDoc.to(baidu.template('tmpl', data), type, {}, "_blank");
     }
     console.log('http://www.xdocin.com/xml.html');
 </script>
 </body>
 </html>  

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

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

截图:

更多参考:

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

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

将HTML导出生成word文档的更多相关文章

  1. PowerDesigner将PDM导出生成WORD文档

    PowerDesigner将PDM导出生成WORD文档 环境 PowerDesigner15 1.点击Report Temlates 制作模板 2.如果没有模板,单击New图标创建.有直接双击进入. ...

  2. 如何在PowerDesigner将PDM导出生成WORD文档或者html文件

    a)         使用PowerDesigner打开pdm文件 b)         点击Report Temlates 制作模板 点击PowerDesigner菜单栏“Report” -> ...

  3. PowerDesigner将PDM导出生成WORD文档--温习老知识

    转:http://www.cnblogs.com/wudiwushen/archive/2010/05/13/1734812.html 今天的温习老知识,是如何将一个PD设计的PDM来导出WORD文档 ...

  4. PowerDesigner将PDM导出生成WORD文档(转)

    今天的温习老知识,是如何将一个PD设计的PDM来导出WORD文档,这是一个非常实用的功能,可以在软件过程的数据库设计文档编写中节省N多时间, 那不废话了,我们就开始今天的讲解吧! 第一步,点击Repo ...

  5. c#生成word文档

    参考:http://blog.163.com/zhouchunping_99/blog/static/7837998820085114394716/ 生成word文档 生成word文档 view pl ...

  6. FreemarkerJavaDemo【Android将表单数据生成Word文档的方案之一(基于freemarker2.3.28,只能java生成)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个方案只能在java中运行,无法在Android项目中运行.所以此方案是:APP将表单数据发送给后台,后台通过freemarker ...

  7. POI加dom4j将数据库的数据按一定格式生成word文档

    一:需求:将从数据库查处来的数据,生成word文档,并有固定的格式.(dom4j的jar包+poi的jar包) 二:解决:(1)先建立固定格式的word文档(2007版本以上),另存成为xml文件,作 ...

  8. java使用freemarker 生成word文档

      java 生成word文档     最近需要做一个导出word的功能, 在网上搜了下, 有用POI,JXL,iText等jar生成一个word文件然后将数据写到该文件中,API非常繁琐而且拼出来的 ...

  9. Aspose.Words简单生成word文档

    Aspose.Words简单生成word文档 Aspose.Words.Document doc = new Aspose.Words.Document(); Aspose.Words.Documen ...

随机推荐

  1. STM32 NVIC配置详解

    例程:  /* Configure one bit for preemption priority */  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ...

  2. JavaIO流文件的操作总结

    IO流的分类 1.根据数据的流向: 输入流:用来读数据,如从外界设备读数据到内存中: 输出流:用来写数据,如从内存输出数据到外界存储设备: 2.根据数据流的格式: 字节流:一般用于声音或者秃瓢等二进制 ...

  3. canvas 绘制 矩形 圆形

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> <tit ...

  4. Git操作指令进阶

    注意: 学习前请先配置好Git客户端 相关文章:Git客户端图文详解如何安装配置GitHub操作流程攻略 官方中文手册:http://git-scm.com/book/zh GIT 学习手册简介 本站 ...

  5. nodejs的mysql模块学习(六)连接池的创建和使用

    介绍 在 软件工程 , 连接池 是一个 高速缓存 的 数据库连接 维持,使得连接可以当需要将来向数据库请求重复使用. [ 来源请求 ] 连接池用于提高数据库上执行命令的性能. 打开并保持每个用户的数据 ...

  6. Android crop image size

    private void performCrop() { try { //call the standard crop action intent (the user device may not s ...

  7. hdu 2509 Be the Winner 博弈论

    博弈论水题!!! 代码如下: #include<stdio.h> #include<iostream> using namespace std; int main(){ int ...

  8. Django部署问题

    1.Debug=True页面正常显示. 2.Debug=False,页面500错误. 3.解决500,配置setting.py,令ALLOWED_HOSTS = ['*'],可解决访问问题,但静态文件 ...

  9. 使用Java管理Azure(1):基础配置

    Azure针对Java开发人员提供了非常丰富的开发库,开发工具,和相关插件,让你通过Java对Azure进行服务管理和开发,本文第一步先介绍如何快速的配置Java开发工具,主要针对目前比较流行的Ecl ...

  10. UVA11387 - The 3-Regular Graph(推理)

    题目链接 题意:给n个点,问能否画出一个无向图.且每一个顶点连接3条边.假设能够的话输出连接的边. 思路:当添加一条边时,总的无向图的度数会添加2,所以度数之和n*2为偶数.当n为奇数时,度数之和为奇 ...