最优雅的方法

感谢评论区大佬netzhouxiang_提供的方法

declare module 'vue-print-nb';

问题

vue项目改造成对typescript支持的项目后,vue-print-nb打印指令无法使用加粗样式
尝试有没有对应的typescript包,发现没有
在这里插入图片描述

解决办法

node_modules目录下找到vue-print-nb,复制出src/packages目录下的print.js和printarea.js。
把他们后缀改成ts,然后内部的类型处理一下。

print.ts

import Print from './printarea';
import Vue from "vue";

Vue.directive("print", {
	inserted: function (el, binding, vnode) {
		let vue: any = vnode.context;
		let closeBtn = true;
		let id = '';
		el.addEventListener('click', () => {
			vue.$nextTick(() => {
				if (typeof binding.value === 'string') {
					id = binding.value;
				} else if (typeof binding.value === 'object' && !!binding.value.id) {
					id = binding.value.id;
					let ids = id.replace(new RegExp("#", "g"), '');
					let elsdom = document.getElementById(ids);
					if (!elsdom) console.log("id in Error"), id = '';
				}
				// 局部打印
				if (id) {
					localPrint();
				} else {
					// 直接全局打印
					window.print();
				}
			});

		});
		const localPrint = () => {
			if (closeBtn) {
				closeBtn = false;
				new Print({
					ids: id, // * 局部打印必传入id
					standard: '', // 文档类型,默认是html5,可选 html5,loose,strict
					extraHead: binding.value.extraHead, // 附加在head标签上的额外标签,使用逗号分隔
					extraCss: binding.value.extraCss, // 额外的css连接,多个逗号分开
					popTitle: binding.value.popTitle, // title的标题
					endCallback() { // 调用打印之后的回调事件
						closeBtn = true;
					}
				});
			}
		};
	}
});

printarea.ts

export default class {
  constructor(option: any) {
    let that: any = this;
    that.standards = {
      strict: 'strict',
      loose: 'loose',
      html5: 'html5'
    };
    that.selectArray = []; // 存储select的
    that.counter = 0;
    that.settings = {
      standard: that.standards.html5,
      extraHead: '', // 附加在head标签上的额外元素,使用逗号分隔
      extraCss: '', // 额外的css逗号分隔
      popTitle: '', // 标题
      endCallback: null, // 成功打开后的回调函数
      ids: '' // 局部打印的id
    };
    Object.assign(that.settings, option);

    that.init();
  }
  init() {
    let that: any = this;
    that.counter++;
    that.settings.id = `printArea_${that.counter}`;
    let PrintAreaWindow = that.getPrintWindow(); // 创建iframe
    that.write(PrintAreaWindow.doc); // 写入内容
    that.print(PrintAreaWindow);
    that.settings.endCallback();

  }
  print(PAWindow: any) {
    let that: any = this;
    let paWindow = PAWindow.win;
    const _loaded = () => {
      paWindow.focus();
      paWindow.print();
      try {
        let box: any = document.getElementById(that.settings.id);
        let canvasList: any = that.elsdom.querySelectorAll('.canvasImg')
        console.log(that.elsdom)
        for (let i = 0; i < canvasList.length; i++) {
          let _parent = canvasList[i].parentNode
          _parent.removeChild(canvasList[i])
        }
        box.parentNode.removeChild(box);
      } catch (e) {
        console.log(e);
      }
    };
    if (window.ActiveXObject) {
      paWindow.onload = _loaded();
      return false;
    }
    paWindow.onload = () => {
      _loaded();
    };
  }
  write(PADocument: any, $ele: any) {
    let that: any = this;
    PADocument.open();
    PADocument.write(`${that.docType()}<html>${that.getHead()}${that.getBody()}</html>`);
    PADocument.close();

  }
  docType() {
    let that: any = this;
    if (that.settings.standard === that.standards.html5) {
      return '<!DOCTYPE html>';
    }
    var transitional = that.settings.standard === that.standards.loose ? ' Transitional' : '';
    var dtd = that.settings.standard === that.standards.loose ? 'loose' : 'strict';

    return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01${transitional}//EN" "http://www.w3.org/TR/html4/${dtd}.dtd">`;
  }
  getHead() {
    let that: any = this;
    let extraHead = '';
    let links = '';
    let style = '';
    if (that.settings.extraHead) {
      that.settings.extraHead.replace(/([^,]+)/g, (m: any) => {
        extraHead += m;
      });
    }
    // 复制所有link标签
    [].forEach.call(document.querySelectorAll('link'), function (item: any, i) {
      if (item.href.indexOf('.css') >= 0) {
        links += `<link type="text/css" rel="stylesheet" href="${item.href}" >`;
      }
    });

    // 循环获取style标签的样式
    let domStyle = document.styleSheets;
    if (domStyle && domStyle.length > 0) {
      for (let i = 0; i < domStyle.length; i++) {
        try {
          if (domStyle[i].cssRules || domStyle[i].rules) {
            let rules = domStyle[i].cssRules || domStyle[i].rules;
            for (let b = 0; b < rules.length; b++) {
              style += rules[b].cssText;
            }
          }
        } catch (e) {
          console.log(domStyle[i].href + e);
        }
      }
    }

    if (that.settings.extraCss) {
      that.settings.extraCss.replace(/([^,\s]+)/g, (m: any) => {
        links += `<link type="text/css" rel="stylesheet" href="${m}">`;
      });

    }

    return `<head><title>${that.settings.popTitle}</title>${extraHead}${links}<style type="text/css">${style}</style></head>`;
  }
  getBody() {
    let that: any = this;
    let ids = that.settings.ids;
    ids = ids.replace(new RegExp("#", "g"), '');
    that.elsdom = that.beforeHanler(document.getElementById(ids));
    let ele = that.getFormData(that.elsdom);
    let htm = ele.outerHTML;
    return '<body>' + htm + '</body>';
  }
  // 克隆节点之前做的操作
  beforeHanler(elsdom: any) {
    let canvasList = elsdom.querySelectorAll('canvas');
    // canvas转换png图片
    for (let i = 0; i < canvasList.length; i++) {
      if (!canvasList[i].style.display) {
        let _parent = canvasList[i].parentNode
        let _canvasUrl = canvasList[i].toDataURL('image/png')
        let _img = new Image()
        _img.className = 'canvasImg'
        _img.style.display = 'none'
        _img.src = _canvasUrl
        // _parent.replaceChild(_img, canvasList[i])
        _parent.appendChild(_img)
      }
    }
    return elsdom
  }
  // 根据type去处理form表单
  getFormData(ele: any) {
    let copy = ele.cloneNode(true);
    let copiedInputs = copy.querySelectorAll('input,select,textarea');
    let canvasImgList = copy.querySelectorAll('.canvasImg,canvas');
    let selectCount = -1;
    // 处理所有canvas
    for (let i = 0; i < canvasImgList.length; i++) {
      let _parent = canvasImgList[i].parentNode
      let item = canvasImgList[i]
      // 删除克隆后的canvas节点
      if (item.tagName.toLowerCase() === 'canvas') {
        _parent.removeChild(item)
      } else {
        item.style.display = 'block'
      }
    }
    // 处理所有输入框
    for (let i = 0; i < copiedInputs.length; i++) {
      let item = copiedInputs[i];
      let typeInput = item.getAttribute('type');
      let copiedInput = copiedInputs[i];
      // 获取select标签
      if (!typeInput) {
        typeInput = item.tagName === 'SELECT' ? 'select' : item.tagName === 'TEXTAREA' ? 'textarea' : '';
      }
      // 处理input框
      if (item.tagName === 'INPUT') {
        // 除了单选框 多选框比较特别
        if (typeInput === 'radio' || typeInput === 'checkbox') {
          copiedInput.setAttribute('checked', item.checked);
          // 
        } else {
          copiedInput.value = item.value;
          copiedInput.setAttribute('value', item.value);
        }
        // 处理select
      } else if (typeInput === 'select') {

        selectCount++;
        for (let b = 0; b < ele.querySelectorAll('select').length; b++) {
          let select = ele.querySelectorAll('select')[b]; // 获取原始层每一个select
          !select.getAttribute('newbs') && select.setAttribute('newbs', b) // 添加标识
          if (select.getAttribute('newbs') == selectCount) {
            let opSelectedIndex = ele.querySelectorAll('select')[selectCount].selectedIndex;
            item.options[opSelectedIndex].setAttribute('selected', true);

          }
        }
        // 处理textarea
      } else {
        copiedInput.innerHTML = item.value;
        copiedInput.setAttribute('html', item.value);
      }
    }

    return copy;
  }
  getPrintWindow() {
    let that: any = this;
    var f = that.Iframe();
    return {
      f: f,
      win: f.contentWindow || f,
      doc: f.doc
    };
  }
  Iframe() {
    let that: any = this;
    let frameId = that.settings.id;
    let iframe: any;
    try {
      iframe = document.createElement('iframe');
      document.body.appendChild(iframe);
      iframe.style.border = '0px';
      iframe.style.position = 'absolute';
      iframe.style.width = '0px';
      iframe.style.height = '0px';
      iframe.style.right = '0px';
      iframe.style.top = '0px';
      iframe.setAttribute('id', frameId);
      iframe.setAttribute('src', new Date().getTime());
      iframe.doc = null;
      iframe.doc = iframe.contentDocument ? iframe.contentDocument : (iframe.contentWindow ? iframe.contentWindow.document : iframe.document);
      iframe.onload = function () {
        var win = iframe.contentWindow || iframe;
        that.print(win);
      }
    } catch (e) {
      throw new Error(e + '. iframes may not be supported in that browser.');
    }

    if (iframe.doc == null) {
      throw new Error('Cannot find document.');
    }

    return iframe;
  }
}

main.ts中直接引入,注意目录结构

import "@/directive/vue-print-nb/print";
Logo

前往低代码交流专区

更多推荐