前言:
项目开发中遇到了需要将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,
7 * license: mit
8 * see
9 */
10
11 /*global self */
12 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
13
14 /*! @source */
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("", "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*;.*charset\s*=\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
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\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>",
8 head: "<head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n<style>\n_styles_\n</style>\n</head>\n",
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 = "\n";
55 for (var i = 0; i < images.length; i++) {
56 mhtmlbottom += "--next.item-boundary\n";
57 mhtmlbottom += "content-location: " + images[i].location + "\n";
58 mhtmlbottom += "content-type: " + images[i].type + "\n";
59 mhtmlbottom += "content-transfer-encoding: " + images[i].encoding + "\n\n";
60 mhtmlbottom += images[i].data + "\n\n";
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, p.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, p.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, p.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, p.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, p.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;}p.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 <p class="word">
9 <p align="center" style="font-size:20pt;font-weight:bold;">js导出word文档</p>
10 </p>
11 <input type="button" value="导出word">
12 <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js?1.1.11"></script>
13 <script type="text/javascript" src="js/filesaver.js?1.1.11"></script>
14 <script type="text/javascript" src="js/jquery.wordexport.js?1.1.11"></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="www.xdocin.com/xdoc.js?1.1.11"></script>
6 <script type="text/javascript" src="http://www.xdocin.com/baidutemplate.js?1.1.11"></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?1.1.11"></script>
37 <script type="text/javascript">
38 var type="docx";//pdf
39 var data = {
40 title: "导出"+type+"文件",
41 img: "",
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('');
56 </script>
57 </body>
58 </html>
这里我通过rendertemplate函数叫js模板渲染到html中,实现了文本的展示和导出内容的结合。而因为这里导出的word文档是需要特别设置样式的,所以在页面样式展示下我们可以通过添加.class的方式设置。
附部分导出word文档样式设置:
截图:
以上就是html怎么导出生成word文档?的详细内容。