美文网首页日常工作Vue
Vue利用print.js插件实现打印功能,并动态设置打印参数

Vue利用print.js插件实现打印功能,并动态设置打印参数

作者: 扶得一人醉如苏沐晨 | 来源:发表于2023-03-24 09:23 被阅读0次

    一、引入print插件

    1.1、新建文件夹和js文件

    • 根目录src下面新建一个plugins文件夹,下面新建一个print.js文件
    • 也可以直接npm安装插件npm install print-js --save,但直接安装的插件配置会有问题,不建议

    print.js代码核心点

    • Vue.prototype的原型链上面注入$print方法
    • $print就是你在页面中调用的方法名称
    const MyPlugin = {};
    MyPlugin.install = function (Vue, options) {
      // 4. 添加实例方法
      Vue.prototype.$print = Print;
    };
    export default MyPlugin;
    

    print.js完整代码

    const Print = function (dom, options) {
      if (!(this instanceof Print)) return new Print(dom, options);
    
      this.options = this.extend(
        {
          noPrint: ".no-print",
          onStart: function () {},
          onEnd: function () {},
        },
        options
      );
    
      if (typeof dom === "string") {
        this.dom = document.querySelector(dom);
      } else {
        this.dom = dom;
      }
    
      this.init();
    };
    Print.prototype = {
      init: function () {
        let content = this.getStyle() + this.getHtml();
        this.writeIframe(content);
      },
      extend: function (obj, obj2) {
        for (let k in obj2) {
          obj[k] = obj2[k];
        }
        return obj;
      },
    
      getStyle: function () {
        let str = "";
        let styles = document.querySelectorAll("style,link");
        for (let i = 0; i < styles.length; i++) {
          str += styles[i].outerHTML;
        }
        str +=
          "<style>" +
          (this.options.noPrint ? this.options.noPrint : ".no-print") +
          "{display:none;}</style>";
    
        return str;
      },
    
      getHtml: function () {
        var inputs = document.querySelectorAll("input");
        var textareas = document.querySelectorAll("textarea");
        var selects = document.querySelectorAll("select");
        let cells = document.querySelectorAll(".cell");
    
        for (var k = 0; k < inputs.length; k++) {
          if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
            if (inputs[k].checked == true) {
              inputs[k].setAttribute("checked", "checked");
            } else {
              inputs[k].removeAttribute("checked");
            }
          } else if (inputs[k].type == "text") {
            inputs[k].setAttribute("value", inputs[k].value);
          } else {
            inputs[k].setAttribute("value", inputs[k].value);
          }
        }
    
        for (var k2 = 0; k2 < textareas.length; k2++) {
          if (textareas[k2].type == "textarea") {
            textareas[k2].innerHTML = textareas[k2].value;
          }
        }
    
        for (var k3 = 0; k3 < selects.length; k3++) {
          if (selects[k3].type == "select-one") {
            var child = selects[k3].children;
            for (var i in child) {
              if (child[i].tagName == "OPTION") {
                if (child[i].selected == true) {
                  child[i].setAttribute("selected", "selected");
                } else {
                  child[i].removeAttribute("selected");
                }
              }
            }
          }
        }
    
        const tableNode = document.querySelectorAll(
          ".el-table__header,.el-table__body"
        );
        console.log(tableNode);
        //el-table 打印预览的时候,宽度占满
        for (let k6 = 0; k6 < tableNode.length; k6++) {
          const tableItem = tableNode[k6];
          tableItem.style.width = "100%";
        }
    
        return this.dom.outerHTML;
      },
    
      writeIframe: function (content) {
        let w;
        let doc;
        let iframe = document.createElement("iframe");
        let f = document.body.appendChild(iframe);
        iframe.id = "myIframe";
        iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
        w = f.contentWindow || f.contentDocument;
        doc = f.contentDocument || f.contentWindow.document;
        doc.open();
        doc.write(content);
        doc.close();
        this.toPrint(w, function () {
          document.body.removeChild(iframe);
        });
      },
    
      toPrint: function (w, cb) {
        let _this = this;
        w.onload = function () {
          try {
            setTimeout(function () {
              w.focus();
              typeof _this.options.onStart === "function" &&
                _this.options.onStart();
              if (!w.document.execCommand("print", false, null)) {
                w.print();
              }
              typeof _this.options.onEnd === "function" && _this.options.onEnd();
              w.close();
              cb && cb();
            });
          } catch (err) {
            console.log("err", err);
          }
        };
      },
    };
    const MyPlugin = {};
    MyPlugin.install = function (Vue, options) {
      // 4. 添加实例方法
      Vue.prototype.$print = Print;
    };
    export default MyPlugin;
    
    

    1.2、main.js引入

    // 导入打印组件
    import Print from "@/plugins/Print";
    Vue.use(Print);
    

    二、使用

    • 通过ref="printArea"绑定打印区域
    • 通过class='noPrint'绑定非打印区域
      如果需要动态调整打印区,如纸张大小和边距啥的
    • 建议使用行内样式配合Vue动态绑定样式实现
      image

    2.1、示例

    <template>
      <div>
        <!-- 通ref节点绑定打印区域 -->
        <div ref="printArea">
          <!-- 定义非打印区域 -->
          <div class="noPrint"></div>
          <!-- 建议使用行内样式动态调整打印区 -->
          <!-- mm为单位更加贴合纸张实际 -->
          <div
            :style="{
              width: form.pageWidth + 'mm',
              height: form.pageHeight + 'mm',
              paddingTop: form.pagePaddingTop + 'mm',
              paddingBottom: form.pagePaddingBottom + 'mm',
              paddingLeft: form.pagePaddingLeft + 'mm',
              paddingRight: form.pagePaddingRight + 'mm',
              margin: '0 auto',
              pageBreakAfter: 'always',
              display: 'flex',
              flexWrap: 'wrap',
              justifyContent: 'flex-start',
              alignContent: 'flex-start',
              background: '#ffffff',
            }"
          ></div>
        </div>
        <div><el-button type="primary" @click="excPrint">打印</el-button></div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          form: {
            // 宽度
            pageWidth: "999",
            // 高度
            pageHeight: "888",
            // 上边距
            pagePaddingTop: "6",
            // 下边距
            pagePaddingBottom: "10",
            // 左边距
            pagePaddingLeft: "20",
            // 右编剧
            pagePaddingRight: "5",
            // 纸张方向
            pagePosition: "1",
            // 书标
            // 宽度
            labelWidth: "28",
            // 高度
            labelHeight: "40",
            // 行间距
            labelRowSpace: "5",
            // 列间距
            labelColSpace: "8",
            // 对齐方式
            labelPosition: "1",
          },
        };
      },
      methods: {
        // 执行打印的方法
        excPrint() {
          // 延迟到下次dom更新执行
          this.$nextTick(() => {
            this.$print(this.$refs["printArea"], {
              noPrint: ".noPrint",
              type: "html",
              // style: style,// 亦可使用引入的外部css;
              onStart: () => {
                console.log("打印开始");
              },
              onEnd: () => {
                console.log("打印完成");
              },
            });
          });
        },
      },
    };
    </script>
    
    <style></style>
    
    

    2.2、@media print设置样式

    注意:这里打印区域的样式需要写成行内样式,不然打印预览不生效
    另外一种办法就是通过@media print{}在里面写样式

    @media print{}就是打印媒体查询,里面的样式只会在打印或者打印预览的时候生效

     <div id="printArea" ref="printArea">
    
    <style lang="scss">
    @media print{
        #printArea{
           color:red;
        }
    }
    </style>
    

    相关文章

      网友评论

        本文标题:Vue利用print.js插件实现打印功能,并动态设置打印参数

        本文链接:https://www.haomeiwen.com/subject/etyirdtx.html