From b63515a396762acb205f836a3b88a83e2f2e4a73 Mon Sep 17 00:00:00 2001 From: xiaoxian521 <1923740402@qq.com> Date: Wed, 22 Dec 2021 17:06:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E3=80=81=E6=B0=B4=E5=8D=B0=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/operate/index.ts | 16 +++ src/utils/print.ts | 216 +++++++++++++++++++++++++++++++++++++ src/utils/watermark.ts | 107 ++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 src/utils/print.ts create mode 100644 src/utils/watermark.ts diff --git a/src/utils/operate/index.ts b/src/utils/operate/index.ts index 13da7cf01..b24788848 100644 --- a/src/utils/operate/index.ts +++ b/src/utils/operate/index.ts @@ -1,3 +1,5 @@ +import type { FunctionArgs } from "@vueuse/core"; + export const hasClass = (ele: RefType, cls: string): any => { return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)")); }; @@ -40,3 +42,17 @@ export const toggleClass = ( className = className.replace(clsName, ""); targetEl.className = flag ? `${className} ${clsName} ` : className; }; + +export function useRafThrottle(fn: T): T { + let locked = false; + // @ts-ignore + return function (...args: any[]) { + if (locked) return; + locked = true; + window.requestAnimationFrame(() => { + // @ts-ignore + fn.apply(this, args); + locked = false; + }); + }; +} diff --git a/src/utils/print.ts b/src/utils/print.ts new file mode 100644 index 000000000..6ff0fe705 --- /dev/null +++ b/src/utils/print.ts @@ -0,0 +1,216 @@ +// 打印类属性、方法定义 +/* eslint-disable */ +const Print = function (dom, options) { + options = options || {}; + // @ts-ignore + if (!(this instanceof Print)) return new Print(dom, options); + this.conf = { + styleStr: "", + setDomHeightArr: [], // 需要动态获取并设置高度的 元素 + echartDomArr: [], // echart dom + printBeforeFn: null, // 打印前回调 + printDoneCallBack: null // 打印后回调 + }; + for (const key in this.conf) { + if (key && options.hasOwnProperty(key)) { + this.conf[key] = options[key]; + } + } + if (typeof dom === "string") { + this.dom = document.querySelector(dom); + } else { + this.dom = this.isDOM(dom) ? dom : dom.$el; + } + if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) { + this.setDomHeight(this.conf.setDomHeightArr); + } + this.init(); +}; + +Print.prototype = { + /** + * 初始化 + */ + init: function () { + var content = this.getStyle() + this.getHtml(); + this.writeIframe(content); + }, + /** + * 配置属性扩展 + * @param {Object} obj + * @param {Object} obj2 + */ + extendOptions: function (obj, obj2) { + for (var k in obj2) { + obj[k] = obj2[k]; + } + return obj; + }, + /** + 复制原网页所有的样式 + */ + getStyle: function () { + var str = "", + styles = document.querySelectorAll("style,link"); + for (var i = 0; i < styles.length; i++) { + str += styles[i].outerHTML; + } + str += ``; + return str; + }, + // 表单赋值 + getHtml: function () { + var inputs = document.querySelectorAll("input"); + var textareas = document.querySelectorAll("textarea"); + var selects = document.querySelectorAll("select"); + // debugger + 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") { + // @ts-ignore + if (child[i].selected == true) { + child[i].setAttribute("selected", "selected"); + } else { + child[i].removeAttribute("selected"); + } + } + } + } + } + + return this.dom.outerHTML; + }, + /** + 创建iframe + */ + writeIframe: function (content) { + // 方法二: + var w, + doc, + iframe = document.createElement("iframe"), + f = document.body.appendChild(iframe); + + iframe.id = "myIframe"; + iframe.setAttribute( + "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(); + var _this = this; + iframe.onload = function () { + // 弹出前,回调 + if (_this.conf.printBeforeFn) { + _this.conf.printBeforeFn({ doc }); + } + + _this.drawEchartImg(doc).then(() => { + _this.toPrint(w); + setTimeout(function () { + document.body.removeChild(iframe); + // 弹出后,回调 + if (_this.conf.printDoneCallBack) { + _this.conf.printDoneCallBack(); + } + }, 100); + }); + }; + }, + /** + * echarts图表打印 + * @param {Object} doc iframe window + */ + drawEchartImg(doc) { + return new Promise((resolve, reject) => { + if (this.conf.echartDomArr && this.conf.echartDomArr.length > 0) { + this.conf.echartDomArr.forEach(e => { + const dom = doc.querySelector("#" + e.$el.id); + const img = new Image(); + const w = dom.offsetWidth + "px"; + const H = dom.offsetHeight + "px"; + + img.style.width = w; + img.style.height = H; + img.src = e.imgSrc; + dom.innerHTML = ""; + dom.appendChild(img); + }); + } + resolve(); + }); + }, + /** + 打印 +*/ + toPrint: function (frameWindow) { + try { + setTimeout(function () { + frameWindow.focus(); + try { + if (!frameWindow.document.execCommand("print", false, null)) { + frameWindow.print(); + } + } catch (e) { + frameWindow.print(); + } + frameWindow.close(); + }, 10); + } catch (err) { + console.error(err); + } + }, + isDOM: + typeof HTMLElement === "object" + ? function (obj) { + return obj instanceof HTMLElement; + } + : function (obj) { + return ( + obj && + typeof obj === "object" && + obj.nodeType === 1 && + typeof obj.nodeName === "string" + ); + }, + /** + * 设置指定dom元素高度,通过获取该dom元素现有高度,并设置 + * @param {Array} arr + */ + setDomHeight(arr) { + if (arr && arr.length) { + arr.forEach(name => { + const domArr = document.querySelectorAll(name); + domArr.forEach(dom => { + dom.style.height = dom.offsetHeight + "px"; + }); + }); + } + } +}; + +export default Print; diff --git a/src/utils/watermark.ts b/src/utils/watermark.ts new file mode 100644 index 000000000..4cfc3c64f --- /dev/null +++ b/src/utils/watermark.ts @@ -0,0 +1,107 @@ +import { + getCurrentInstance, + onBeforeUnmount, + ref, + Ref, + shallowRef, + unref +} from "vue"; +import { useRafThrottle } from "/@/utils/operate"; +import { addResizeListener, removeResizeListener } from "/@/utils/resize"; +import { isDef } from "/@/utils/is"; + +const domSymbol = Symbol("watermark-dom"); + +export function useWatermark( + appendEl: Ref = ref(document.body) as Ref +) { + const func = useRafThrottle(function () { + const el = unref(appendEl); + if (!el) return; + const { clientHeight: height, clientWidth: width } = el; + updateWatermark({ height, width }); + }); + const id = domSymbol.toString(); + const watermarkEl = shallowRef(); + + const clear = () => { + const domId = unref(watermarkEl); + watermarkEl.value = undefined; + const el = unref(appendEl); + if (!el) return; + domId && el.removeChild(domId); + removeResizeListener(el, func); + }; + + function createBase64(str: string) { + const can = document.createElement("canvas"); + const width = 300; + const height = 240; + Object.assign(can, { width, height }); + + const cans = can.getContext("2d"); + if (cans) { + cans.rotate((-20 * Math.PI) / 120); + cans.font = "15px Vedana"; + cans.fillStyle = "rgba(0, 0, 0, 0.15)"; + cans.textAlign = "left"; + cans.textBaseline = "middle"; + cans.fillText(str, width / 20, height); + } + return can.toDataURL("image/png"); + } + + function updateWatermark( + options: { + width?: number; + height?: number; + str?: string; + } = {} + ) { + const el = unref(watermarkEl); + if (!el) return; + if (isDef(options.width)) { + el.style.width = `${options.width}px`; + } + if (isDef(options.height)) { + el.style.height = `${options.height}px`; + } + if (isDef(options.str)) { + el.style.background = `url(${createBase64(options.str)}) left top repeat`; + } + } + + const createWatermark = (str: string) => { + if (unref(watermarkEl)) { + updateWatermark({ str }); + return id; + } + const div = document.createElement("div"); + watermarkEl.value = div; + div.id = id; + div.style.pointerEvents = "none"; + div.style.top = "0px"; + div.style.left = "0px"; + div.style.position = "absolute"; + div.style.zIndex = "100000"; + const el = unref(appendEl); + if (!el) return id; + const { clientHeight: height, clientWidth: width } = el; + updateWatermark({ str, width, height }); + el.appendChild(div); + return id; + }; + + function setWatermark(str: string) { + createWatermark(str); + addResizeListener(document.documentElement, func); + const instance = getCurrentInstance(); + if (instance) { + onBeforeUnmount(() => { + clear(); + }); + } + } + + return { setWatermark, clear }; +}