vue html转word

网页转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>
导出word效果.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容