vue前端实现导出页面为word(两种方法)

将vue页面导出为word文档,不用写模板,直接导出即可。

第一种方法(简单版)

第一步:安装所需依赖

复制代码
npm install html-docx-js -S
npm install file-saver -S

第二步:创建容器,页面使用方法(简单版:导出内容为纯文字,没有表格、图片这些东西)

第二步:创建容器,页面使用方法(复杂版:导出内容带有表格和图片的情况 【使用了tinymce富文本编辑器会有表格和图片,然后需要导出带有表格和图片的word文档】)

注意:使用v-html更新元素的 innerHTML,html结构会被解析为标签
以下是需要导出的内容(exportContent):

复制代码
 <div 
    id="managerReport"
    class="checkInfoStyle">
    <div v-html="exportContent"></div>
 </div>

把exportContent 内容导出为word文档
下边直接写导出方法了:

复制代码
    // 第一种方法
    wordDownload1 () {
      this.$nextTick(() => {
        const htmlContent = document.getElementById("managerReport") // managerReport id要对应
        // 注意:直接导出表格没有边框并且不是100%撑满的,所以需要做以下的处理
        // 查找并修改表格的样式
        const tables = htmlContent.querySelectorAll('table');
        tables.forEach(table => {
          table.style.borderCollapse = 'collapse'
          table.style.width = '100%'

          table.querySelectorAll('td, th').forEach((cell, index) => {
            if (cell){
              cell.style.border = '1px solid black'
              cell.style.padding = '8px'
            }
          })
        })

		// 拿到需要导出的内容
        let htmlString = htmlContent.innerHTML
        // 注意:以下操作是为了解决导出内容为两端对齐的情况,如果导出内容某一行中有几个字,那这几个字就会两端对齐,格式就错乱了
        // 考虑到是因为<br>标签才会两端对齐,所以做如下的操作(去除<br>标签[br标签是换行标签],把内容加到<div>标签内)
        const regex = /([^>]*?)<br.*?>/gi;  // 找到结束标签 ' <br /> ' 和开始标签 ' > ' 中间的内容,把这部分内容放到div标签内
        htmlString = htmlString.replace(regex, (match, p1) => { // p1就是找到的br标签中间的内容
          let ret = ''
          if (p1.trim()){
            ret += `<div>${p1}</div>` // 把找到的内容放到div标签内
          } else {
            ret += `<div>&nbsp;</div>` // 不加此步骤,如果导出内容中间有空行就会解析不了,直接吞掉空行了
          }
          return ret
        })
        // 将HTML转换为Blob对象
        const blob = htmlDocx.asBlob(htmlString);
        saveAs(blob, `${this.editData.cTopicC}(${this.editData.dDate}).docx`)
      })
    },


   // 第二种方法
    wordDownload2 () {
      this.$nextTick(() => {
        const htmlContent = document.getElementById("managerReport")

        // 查找并修改表格的样式
        const tables = htmlContent.querySelectorAll('table')
        tables.forEach(table => {
          table.style.borderCollapse = 'collapse'
          table.style.width = '100%'

          table.querySelectorAll('td, th').forEach((cell, index) => {
            if (cell){
              cell.style.border = '1px solid black'
              cell.style.padding = '8px'
            }
          })
        })

        //去除<br>标签,内容加到<div>标签内
        const brs = htmlContent.querySelectorAll('br')
        brs.forEach(br => {
          const parent = br.parentNode                  //获取父节点
          let textNode = br.previousSibling             //前一个兄弟节点
          // while (textNode && textNode.nodeType !== Node.TEXT_NODE) {
          //   textNode = textNode.previousSibling;        //循环查找,直到找到一个文本节点或没有更多的兄弟节点
          // }
          if (textNode && textNode.nodeType === Node.TEXT_NODE && textNode.textContent.trim()){ //找到文本节点,并且内容不为空
            const div = document.createElement('div')
            div.textContent = textNode.textContent
            parent.insertBefore(div, br)

            parent.removeChild(textNode)                //移除原有的文本节点,避免内容重复
          } else {
            const div = document.createElement('div')
            div.innerHTML = '&nbsp;'
            parent.insertBefore(div, br)
          }
          parent.removeChild(br)
        })

        const htmlContentCopy = htmlContent.cloneNode(true)

        const imgs = htmlContentCopy.querySelectorAll('img')
        imgs.forEach(img => {
          let docxWidth = 620
          if (img.width > docxWidth){
            img.height = img.height * docxWidth / img.width
            img.width = docxWidth
          }
        })

        // 将HTML转换为Blob对象
        const blob = htmlDocx.asBlob(htmlContentCopy.innerHTML)
        saveAs(blob, `${this.editData.cTopicC}(${this.editData.dDate}).docx`)
      })
    },

注意:在当前页面引入依赖

复制代码
import FileSaver from "file-saver"; 
import htmlDocx from "html-docx-js/dist/html-docx";**

问题:用此方法,最近遇到了一个问题,就是导出内容很少的情况,比如:导出内容只有一行或者两行、三行,并且每行只有几个字的情况,导出内容就成乱码了。如果有遇到此种情况并且有解决方案的大佬,感谢评论区分享。


第二种方法(需要使用jquery)

第一步:安装所需依赖

复制代码
npm install jquery --save
npm install file-saver

第二步:创建两个js文件,一个是jquery文件(jq.js),一个是插件js的文件(jquery.wordexport.js),我把这两个js文件都放到utils文件夹下,注意:使用的时候一定要注意引用路径。这两个js文件代码我都放到文章最后(有一个插件没有依赖包,所以需要自己创建一个js文件(jquery.wordexport.js))

第三步:在需要导出的页面引入文件

复制代码
import $ from "@/utils/jq"; // 文件引入路径一定要正确,这是第二步创建的js文件(jq.js)
import saveAs from "file-saver/dist/FileSaver";
import "@/utils/jquery.wordexport"; // 文件引入路径一定要正确,这是第二步创建的js文件(jquery.wordexport.js)

第四步:页面使用方法

注意:如果导出的时候出现bug,大多是因为文件路径引入有问题,再次排查路径引入

jq.js

复制代码
import $ from "jquery";
  window.$ = $;
  window.jQuery = $;
export default $;

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
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 xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
_html_</html>',
                  head:
                    '<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
_styles_
</style>
<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:TrackMoves>false</w:TrackMoves><w:TrackFormatting/><w:ValidateAgainstSchemas/><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:DoNotPromoteQF/><w:LidThemeOther>EN-US</w:LidThemeOther><w:LidThemeAsian>ZH-CN</w:LidThemeAsian><w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript><w:Compatibility><w:BreakWrappedTables/><w:SnapToGridInCell/><w:WrapTextWithPunct/><w:UseAsianBreakRules/><w:DontGrowAutofit/><w:SplitPgBreakAndParaMark/><w:DontVertAlignCellWithSp/><w:DontBreakConstrainedForcedTables/><w:DontVertAlignInTxbx/><w:Word11KerningPairs/><w:CachedColBalance/><w:UseFELayout/></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><m:mathPr><m:mathFont m:val="Cambria Math"/><m:brkBin m:val="before"/><m:brkBinSub m:val="--"/><m:smallFrac m:val="off"/><m:dispDef/><m:lMargin m:val="0"/> <m:rMargin m:val="0"/><m:defJc m:val="centerGroup"/><m:wrapIndent m:val="1440"/><m:intLim m:val="subSup"/><m:naryLim m:val="undOvr"/></m:mathPr></w:WordDocument></xml><![endif]--></head>
',
                  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');
          // var img = new Image(); 用这一行的话,WPS不显示图片,用上面的------只兼容office Word。
          var mhtmlBottom = "
";
          for (var i = 0; i < img.length; i++) {
              // Calculate dimensions of output image
              var w = Math.min(img[i].width == 0 ? options.maxWidth : img[i].width, options.maxWidth);
              var h = (img[i].height == 0 ? options.defaultLength : img[i].height) * (w / (img[i].width == 0 ? options.maxWidth : 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], 0, 0, w, h);
              // Get data URL encoding of image
              var uri = canvas.toDataURL("image/png");
              // console.log(i+":"+uri);
              $(img[i]).attr("src", img[i].src);
              img[i].width = w;
              img[i].height = h;

              mhtmlBottom += "--NEXT.ITEM-BOUNDARY
";
              mhtmlBottom += "Content-Location: " + uri + "
";
              mhtmlBottom += "Content-Type: " + uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")) + "
";
              mhtmlBottom += "Content-Transfer-Encoding: " + uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")) + "

";
              mhtmlBottom += uri.substring(uri.indexOf(",") + 1) + "

";
          }

          mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";

          //TODO: load css from included stylesheet
          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"); // 注意:不要改成docx,不然会打不开!!!
          
      };
  })(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)");
  }
}
相关推荐
码客前端4 分钟前
理解 Flex 布局中的 flex:1 与 min-width: 0 问题
前端·css·css3
Komorebi゛4 分钟前
【CSS】圆锥渐变流光效果边框样式实现
前端·css
工藤学编程17 分钟前
零基础学AI大模型之CoT思维链和ReAct推理行动
前端·人工智能·react.js
徐同保17 分钟前
上传文件,在前端用 pdf.js 提取 上传的pdf文件中的图片
前端·javascript·pdf
怕浪猫18 分钟前
React从入门到出门第四章 组件通讯与全局状态管理
前端·javascript·react.js
内存不泄露24 分钟前
基于Spring Boot和Vue 3的智能心理健康咨询平台设计与实现
vue.js·spring boot·后端
欧阳天风26 分钟前
用setTimeout代替setInterval
开发语言·前端·javascript
EndingCoder29 分钟前
箭头函数和 this 绑定
linux·前端·javascript·typescript
郑州光合科技余经理30 分钟前
架构解析:同城本地生活服务o2o平台海外版
大数据·开发语言·前端·人工智能·架构·php·生活
沐墨染32 分钟前
大型数据分析组件前端实践:多维度检索与实时交互设计
前端·elementui·数据挖掘·数据分析·vue·交互