网页转word,一般都是将网页标签内容复制到word中,存在主要的两个问题:1. 页面样式丢失 2. 页面图片丢失,如果页面中有图表就更悲剧了; 如果是网页转pdf,现在技术比较成熟,html2Canvas就搞定了。
对于网页中的图片与图标资源,要想展示在word中,只有一种方案,那就是通过转换为图片的base64形式。
进入正题,直接上vue代码:
定义word导出组件
//导入js文件
import saveAs from "file-saver"
import $ from "jquery"
if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
(function() {
$.fn.wordExport = function(fileName,rules) {
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: 624
};
// 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');
console.log(img.length)
for (var i = 0; i < img.length; i++) {
// calc word show size
var w = Math.min(img[i].width, options.maxWidth);
var h = img[i].height * (w / img[i].width);
// $(img[i]).attr("src", uri);
img[i].width = w;
img[i].height = h;
// base64 直接显示即可
var uri = img[i].src;
// Save encoded image to array
images[i] = {
type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
location: img[i].src,
data: uri.substring(uri.indexOf(",") + 1)
};
}
// Prepare bottom of mhtml file with image data
var mhtmlBottom = "\n";
for (var i = 0; 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 = rules;
// 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.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)");
}
}
测试页面
<template>
<div>
<button v-on:click="downLoad">downLoad</button>
<button v-on:click="showImg">showImg</button>
<div id="word" class="hello">
<h1 style="text-align:center;">{{ msg }}</h1>
<h2>我是柱状图</h2>
<div>
<img
id="showImg"
v-if="imgBase64 != ''"
:src="imgBase64"
style="width:600px; height:300px;"
/>
</div>
<div
ref="charts"
id="charts"
style="width:600px; height:300px;margin: 0 auto;"
></div>
<h2>我是表格</h2>
<table style="width:100%; border-collapse:collapse;" border="1px">
<tr>
<td>列头1</td>
<td>列头2</td>
<td>列头3</td>
<td>列头4</td>
<td>列头5</td>
</tr>
<tr>
<td>列头1</td>
<td>列头2</td>
<td>列头3</td>
<td>列头4</td>
<td>列头5</td>
</tr>
<tr>
<td>列头1</td>
<td>列头2</td>
<td>列头3</td>
<td>列头4</td>
<td>列头5</td>
</tr>
<tr>
<td>列头1</td>
<td>列头2</td>
<td>列头3</td>
<td>列头4</td>
<td>列头5</td>
</tr>
</table>
<h2>我是饼图</h2>
<div>
<img
id="showImg2"
v-if="imgBase642 != ''"
:src="imgBase642"
style="width:600px; height:300px;"
/>
</div>
<div
ref="charts2"
id="charts2"
style="width:600px; height:300px;margin: 0 auto;"
></div>
</div>
</div>
</template>
<script>
import $ from "jquery";
import saveAs from "file-saver";
import wordExport from "@/utils/word.export";
import echarts from "echarts";
export default {
name: "HelloWorld",
data() {
return {
option2: {
title: {
text: "某站点用户访问来源",
subtext: "纯属虚构",
left: "center"
},
tooltip: {
trigger: "item"
},
legend: {
orient: "vertical",
left: "left"
},
series: [
{
name: "访问来源",
type: "pie",
radius: "50%",
data: [
{ value: 1048, name: "搜索引擎" },
{ value: 735, name: "直接访问" },
{ value: 580, name: "邮件营销" },
{ value: 484, name: "联盟广告" },
{ value: 300, name: "视频广告" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
},
msg: "Welcome to Your Vue.js App",
imgBase64: "",
imgBase642: "",
myChart2: null,
myChart: null
};
},
mounted() {
console.log("mounted");
this.mycharts();
},
methods: {
downLoad() {
this.showImg();
setTimeout(function() {
$("#word").wordExport("网页导出"); //参数是下载的word文件名
}, 1000);
},
showImg() {
var dataURL = this.myChart.getConnectedDataURL({
type: "png",
pixelRatio: 2, //放大n倍
backgroundColor: "#fff"
});
$("#charts").hide();
this.imgBase64 = dataURL;
var dataURL2 = this.myChart2.getConnectedDataURL({
type: "png",
pixelRatio: 2, //放大n倍
backgroundColor: "#fff"
});
$("#charts2").hide();
this.imgBase642 = dataURL2;
},
mycharts() {
let myChart = echarts.init(this.$refs.charts, "macarons");
myChart.setOption({
color: [
"rgb(8,252,7)",
"rgb(255,168,0)",
"rgb(0,121,254)",
"rgb(0,255,251)"
],
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
crossStyle: {
color: "#999"
}
},
position: function(pt) {
//提示框的位置
return [pt[0], 30];
}
},
grid: {
//图表和父盒子之间的距离
left: "3%",
right: "4%",
bottom: "3%",
top: "2%",
containLabel: true
},
xAxis: {
//x轴
type: "category",
// boundaryGap: false,
data: [
"供电煤耗",
"综合厂用电率",
"发电厂用电率",
"发电水耗率",
"发电油耗率"
],
axisLabel: {
interval: 0,
textStyle: {
color: "#000",
fontSize: 10
},
margin: 8
},
axisLine: {
show: true,
lineStyle: {
color: "rgb(2,121,253)"
}
},
axisTick: {
show: false
}
},
yAxis: {
type: "value",
axisLabel: {
//x轴的坐标文字
show: true,
textStyle: {
color: "#000" //文字的颜色
}
},
max: 100,
axisLine: {
show: true,
lineStyle: {
color: "rgb(2,121,253)"
}
},
axisTick: {
show: false
},
splitLine: {
//坐标在grid区域的分割线
lineStyle: {
//设置分割线的样式(图表横线颜色)
color: ["#153a8a"]
}
}
},
series: [
{
name: "完成值",
type: "bar", //柱状图
data: [30, 40, 50, 60, 70],
barWidth: "8%" //柱状体的宽度
},
{
name: "计划值",
type: "bar",
data: [20, 50, 60, 40, 40],
barWidth: "8%"
},
{
name: "同期值",
type: "bar",
data: [60, 50, 40, 30, 20],
barWidth: "8%"
},
{
name: "上期值",
type: "bar",
data: [50, 70, 60, 30, 40],
barWidth: "8%"
}
]
});
this.myChart = myChart;
let myChart2 = echarts.init(this.$refs.charts2, "macarons");
myChart2.setOption(this.option2);
this.myChart2 = myChart2;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1,
h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
.righttop {
width: 100%;
height: 100%;
}
</style>