print.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. interface PrintFunction {
  2. extendOptions: Function;
  3. getStyle: Function;
  4. setDomHeight: Function;
  5. toPrint: Function;
  6. }
  7. const Print = function (dom, options?: object): PrintFunction {
  8. options = options || {};
  9. // @ts-expect-error
  10. if (!(this instanceof Print)) return new Print(dom, options);
  11. this.conf = {
  12. styleStr: "",
  13. // Elements that need to dynamically get and set the height
  14. setDomHeightArr: [],
  15. // Callback before printing
  16. printBeforeFn: null,
  17. // Callback after printing
  18. printDoneCallBack: null
  19. };
  20. for (const key in this.conf) {
  21. // eslint-disable-next-line no-prototype-builtins
  22. if (key && options.hasOwnProperty(key)) {
  23. this.conf[key] = options[key];
  24. }
  25. }
  26. if (typeof dom === "string") {
  27. this.dom = document.querySelector(dom);
  28. } else {
  29. this.dom = this.isDOM(dom) ? dom : dom.$el;
  30. }
  31. if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) {
  32. this.setDomHeight(this.conf.setDomHeightArr);
  33. }
  34. this.init();
  35. };
  36. Print.prototype = {
  37. /**
  38. * init
  39. */
  40. init: function (): void {
  41. const content = this.getStyle() + this.getHtml();
  42. this.writeIframe(content);
  43. },
  44. /**
  45. * Configuration property extension
  46. * @param {Object} obj
  47. * @param {Object} obj2
  48. */
  49. extendOptions: function <T>(obj, obj2: T): T {
  50. for (const k in obj2) {
  51. obj[k] = obj2[k];
  52. }
  53. return obj;
  54. },
  55. /**
  56. Copy all styles of the original page
  57. */
  58. getStyle: function (): string {
  59. let str = "";
  60. const styles: NodeListOf<Element> = document.querySelectorAll("style,link");
  61. for (let i = 0; i < styles.length; i++) {
  62. str += styles[i].outerHTML;
  63. }
  64. str += `<style>.no-print{display:none;}${this.conf.styleStr}</style>`;
  65. return str;
  66. },
  67. // form assignment
  68. getHtml: function (): Element {
  69. const inputs = document.querySelectorAll("input");
  70. const selects = document.querySelectorAll("select");
  71. const textareas = document.querySelectorAll("textarea");
  72. const canvass = document.querySelectorAll("canvas");
  73. for (let k = 0; k < inputs.length; k++) {
  74. if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
  75. if (inputs[k].checked == true) {
  76. inputs[k].setAttribute("checked", "checked");
  77. } else {
  78. inputs[k].removeAttribute("checked");
  79. }
  80. } else if (inputs[k].type == "text") {
  81. inputs[k].setAttribute("value", inputs[k].value);
  82. } else {
  83. inputs[k].setAttribute("value", inputs[k].value);
  84. }
  85. }
  86. for (let k2 = 0; k2 < textareas.length; k2++) {
  87. if (textareas[k2].type == "textarea") {
  88. textareas[k2].innerHTML = textareas[k2].value;
  89. }
  90. }
  91. for (let k3 = 0; k3 < selects.length; k3++) {
  92. if (selects[k3].type == "select-one") {
  93. const child = selects[k3].children;
  94. for (const i in child) {
  95. if (child[i].tagName == "OPTION") {
  96. if ((child[i] as any).selected == true) {
  97. child[i].setAttribute("selected", "selected");
  98. } else {
  99. child[i].removeAttribute("selected");
  100. }
  101. }
  102. }
  103. }
  104. }
  105. for (let k4 = 0; k4 < canvass.length; k4++) {
  106. const imageURL = canvass[k4].toDataURL("image/png");
  107. const img = document.createElement("img");
  108. img.src = imageURL;
  109. img.setAttribute("style", "max-width: 100%;");
  110. img.className = "isNeedRemove";
  111. canvass[k4].parentNode.insertBefore(img, canvass[k4].nextElementSibling);
  112. }
  113. return this.dom.outerHTML;
  114. },
  115. /**
  116. create iframe
  117. */
  118. writeIframe: function (content) {
  119. let w: Document | Window;
  120. let doc: Document;
  121. const iframe: HTMLIFrameElement = document.createElement("iframe");
  122. const f: HTMLIFrameElement = document.body.appendChild(iframe);
  123. iframe.id = "myIframe";
  124. iframe.setAttribute(
  125. "style",
  126. "position:absolute;width:0;height:0;top:-10px;left:-10px;"
  127. );
  128. // eslint-disable-next-line prefer-const
  129. w = f.contentWindow || f.contentDocument;
  130. // eslint-disable-next-line prefer-const
  131. doc = f.contentDocument || f.contentWindow.document;
  132. doc.open();
  133. doc.write(content);
  134. doc.close();
  135. const removes = document.querySelectorAll(".isNeedRemove");
  136. for (let k = 0; k < removes.length; k++) {
  137. removes[k].parentNode.removeChild(removes[k]);
  138. }
  139. // eslint-disable-next-line @typescript-eslint/no-this-alias
  140. const _this = this;
  141. iframe.onload = function (): void {
  142. // Before popping, callback
  143. if (_this.conf.printBeforeFn) {
  144. _this.conf.printBeforeFn({ doc });
  145. }
  146. _this.toPrint(w);
  147. setTimeout(function () {
  148. document.body.removeChild(iframe);
  149. // After popup, callback
  150. if (_this.conf.printDoneCallBack) {
  151. _this.conf.printDoneCallBack();
  152. }
  153. }, 100);
  154. };
  155. },
  156. /**
  157. Print
  158. */
  159. toPrint: function (frameWindow): void {
  160. try {
  161. setTimeout(function () {
  162. frameWindow.focus();
  163. try {
  164. if (!frameWindow.document.execCommand("print", false, null)) {
  165. frameWindow.print();
  166. }
  167. } catch (e) {
  168. frameWindow.print();
  169. }
  170. frameWindow.close();
  171. }, 10);
  172. } catch (err) {
  173. console.error(err);
  174. }
  175. },
  176. isDOM:
  177. typeof HTMLElement === "object"
  178. ? function (obj) {
  179. return obj instanceof HTMLElement;
  180. }
  181. : function (obj) {
  182. return (
  183. obj &&
  184. typeof obj === "object" &&
  185. obj.nodeType === 1 &&
  186. typeof obj.nodeName === "string"
  187. );
  188. },
  189. /**
  190. * Set the height of the specified dom element by getting the existing height of the dom element and setting
  191. * @param {Array} arr
  192. */
  193. setDomHeight(arr) {
  194. if (arr && arr.length) {
  195. arr.forEach(name => {
  196. const domArr = document.querySelectorAll(name);
  197. domArr.forEach(dom => {
  198. dom.style.height = dom.offsetHeight + "px";
  199. });
  200. });
  201. }
  202. }
  203. };
  204. export default Print;