w-vue3-watermark 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/package.json +1 -1
- package/watermark.common.js +49 -28
- package/watermark.common.js.map +1 -1
- package/watermark.umd.js +49 -28
- package/watermark.umd.js.map +1 -1
- package/watermark.umd.min.js +1 -1
- package/watermark.umd.min.js.map +1 -1
package/README.md
CHANGED
|
@@ -41,11 +41,12 @@ createApp(App).use(watermark).mount('xxxx')
|
|
|
41
41
|
| waterName | 水印内容 | - | [string, array]|
|
|
42
42
|
| waterFontSize | 水印字体大小 | 20 | number |
|
|
43
43
|
| waterFontWeight| 水印字体粗细 | 700 | number |
|
|
44
|
-
| waterGap | 水印重复的间隔 |
|
|
45
|
-
| waterRotate | 水印倾斜角度 |
|
|
44
|
+
| waterGap | 水印重复的间隔 | 100 | number |
|
|
45
|
+
| waterRotate | 水印倾斜角度 | 20 | number |
|
|
46
46
|
| waterFontFamily| 水印字体 | Microsoft Yahei | string |
|
|
47
47
|
| waterFontColor | 水印字体颜色 | rgba(255, 255, 255, 1)| string |
|
|
48
48
|
| shadowColor | 水印阴影颜色 | rgba(61, 61, 61, 0.25)| string |
|
|
49
49
|
| shadowOffsetX | 阴影水平偏移 | 1.5 | number |
|
|
50
50
|
| shadowOffsetY | 阴影垂直偏移 | 1.5 | number |
|
|
51
51
|
| shadowBlur | 阴影模糊半径 | 0 | number |
|
|
52
|
+
| waterTextAlign | 水印对齐方式 | left | string |
|
package/package.json
CHANGED
package/watermark.common.js
CHANGED
|
@@ -94,62 +94,78 @@ function useWatermarkBg(props) {
|
|
|
94
94
|
// 遍历数组,逐个测量并比较宽度
|
|
95
95
|
for (let i = 1; i < textArr.length; i++) {
|
|
96
96
|
const currentText = textArr[i];
|
|
97
|
-
// 测量当前文本的宽度
|
|
98
97
|
const currentWidth = ctx.measureText(currentText).width;
|
|
99
|
-
|
|
100
|
-
// 比较当前宽度与已记录的最大宽度
|
|
101
98
|
if (currentWidth > maxWidth) {
|
|
102
|
-
// 更新最大宽度和对应的最长文本
|
|
103
99
|
maxWidth = currentWidth;
|
|
104
100
|
longestText = currentText;
|
|
105
101
|
}
|
|
106
102
|
}
|
|
107
|
-
|
|
108
|
-
// 返回结果(包含最长文本和最大宽度,方便后续使用)
|
|
109
103
|
return {
|
|
110
104
|
longestText,
|
|
111
105
|
maxWidth
|
|
112
106
|
};
|
|
113
107
|
}
|
|
114
108
|
return (0,external_commonjs_vue_commonjs2_vue_root_Vue_namespaceObject.computed)(() => {
|
|
115
|
-
// 创建一个 canvas
|
|
116
109
|
const canvas = document.createElement('canvas');
|
|
117
110
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
118
|
-
// 设置字体大小
|
|
119
111
|
const fontSize = props.waterFontSize * devicePixelRatio;
|
|
120
|
-
const font = props.waterFontWeight
|
|
112
|
+
const font = `${props.waterFontWeight} ${fontSize}px ${props.waterFontFamily}`;
|
|
121
113
|
const ctx = canvas.getContext('2d');
|
|
122
|
-
//
|
|
114
|
+
const waterGap = props.waterGap * devicePixelRatio; // 统一缓存适配后的间距
|
|
115
|
+
|
|
116
|
+
// 第一步:先设置字体,测量文字最大宽度
|
|
123
117
|
ctx.font = font;
|
|
124
118
|
const {
|
|
125
119
|
maxWidth
|
|
126
120
|
} = getLongestTextByWidth(props.waterName, ctx);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
121
|
+
|
|
122
|
+
// 第二步:精准计算 Canvas 尺寸(平衡左右上下空间,无冗余浪费)
|
|
123
|
+
// 核心:基于文字实际宽度+字体大小+间距,计算旋转后刚好容纳的画布尺寸
|
|
124
|
+
const textTotalWidth = maxWidth; // 文字原始最大宽度
|
|
125
|
+
const textTotalHeight = Array.isArray(props.waterName) ? (props.waterName.length - 1) * (fontSize + 6 * devicePixelRatio) + fontSize : fontSize; // 文字整体高度(多行文适配)
|
|
126
|
+
// 画布基础尺寸:文字整体尺寸 + 双向间距(左右/上下各留一份gap,避免贴边)
|
|
127
|
+
const baseCanvasSize = Math.max(100, Math.sqrt(textTotalWidth ** 2 + textTotalHeight ** 2)) + waterGap * 2;
|
|
128
|
+
canvas.width = baseCanvasSize;
|
|
129
|
+
canvas.height = baseCanvasSize;
|
|
130
|
+
|
|
131
|
+
// 第三步:重置上下文,配置样式(保持原有功能不变)
|
|
132
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
134
133
|
ctx.font = font;
|
|
135
|
-
ctx.
|
|
134
|
+
ctx.fillStyle = props.waterFontColor;
|
|
135
|
+
ctx.textAlign = props.waterTextAlign;
|
|
136
136
|
ctx.textBaseline = 'middle';
|
|
137
|
-
ctx.shadowColor = props.shadowColor;
|
|
138
|
-
ctx.shadowOffsetX = props.shadowOffsetX;
|
|
139
|
-
ctx.shadowOffsetY = props.shadowOffsetY;
|
|
140
|
-
ctx.shadowBlur = props.shadowBlur;
|
|
141
|
-
|
|
137
|
+
ctx.shadowColor = props.shadowColor;
|
|
138
|
+
ctx.shadowOffsetX = props.shadowOffsetX;
|
|
139
|
+
ctx.shadowOffsetY = props.shadowOffsetY;
|
|
140
|
+
ctx.shadowBlur = props.shadowBlur;
|
|
141
|
+
|
|
142
|
+
// 第四步:核心修复——合理设置旋转中心+最小必要偏移(平衡左右上下)
|
|
143
|
+
// 1. 旋转中心移至画布「左侧中间偏上」(而非中心),避免左右空间失衡
|
|
144
|
+
// 2. 仅预留最小必要偏移(waterGap),既避免左上角截取,又不挤占右侧空间
|
|
145
|
+
const safeOffset = waterGap; // 安全偏移量(最小必要,兼顾上下左右)
|
|
146
|
+
ctx.translate(safeOffset, canvas.height / 2); // 水平仅偏移安全间距,垂直居中
|
|
147
|
+
|
|
148
|
+
// 旋转水印(保持原有配置,无过度偏移)
|
|
149
|
+
ctx.rotate(Math.PI / 180 * -props.waterRotate);
|
|
150
|
+
|
|
151
|
+
// 第五步:绘制文字(基于安全偏移,无过度靠右,保证右侧完整)
|
|
142
152
|
if (Array.isArray(props.waterName)) {
|
|
143
153
|
props.waterName.forEach((item, index) => {
|
|
144
|
-
|
|
154
|
+
// 垂直间距:适配设备像素比,保持原有排版逻辑
|
|
155
|
+
const verticalGap = fontSize + 6 * devicePixelRatio;
|
|
156
|
+
// 绘制起点:(0, index*verticalGap),无额外水平偏移,避免右侧溢出
|
|
157
|
+
ctx.fillText(item, 0, index * verticalGap);
|
|
145
158
|
});
|
|
146
159
|
} else {
|
|
160
|
+
// 单文本直接绘制,起点(0,0),基于已有的safeOffset保证左上角不截取
|
|
147
161
|
ctx.fillText(props.waterName, 0, 0);
|
|
148
162
|
}
|
|
163
|
+
|
|
164
|
+
// 返回水印信息
|
|
149
165
|
return {
|
|
150
166
|
base64: canvas.toDataURL(),
|
|
151
|
-
size:
|
|
152
|
-
styleSize:
|
|
167
|
+
size: baseCanvasSize,
|
|
168
|
+
styleSize: baseCanvasSize / devicePixelRatio
|
|
153
169
|
};
|
|
154
170
|
});
|
|
155
171
|
}
|
|
@@ -181,18 +197,23 @@ const __default__ = {
|
|
|
181
197
|
waterGap: {
|
|
182
198
|
// 水印重复的间隔
|
|
183
199
|
type: Number,
|
|
184
|
-
default:
|
|
200
|
+
default: 100
|
|
185
201
|
},
|
|
186
202
|
waterRotate: {
|
|
187
203
|
// 水印倾斜
|
|
188
204
|
type: Number,
|
|
189
|
-
default:
|
|
205
|
+
default: 20
|
|
190
206
|
},
|
|
191
207
|
waterFontFamily: {
|
|
192
208
|
// 水印字体
|
|
193
209
|
type: String,
|
|
194
210
|
default: "Microsoft Yahei"
|
|
195
211
|
},
|
|
212
|
+
waterTextAlign: {
|
|
213
|
+
// 水印对齐方式
|
|
214
|
+
type: String,
|
|
215
|
+
default: "left"
|
|
216
|
+
},
|
|
196
217
|
waterFontColor: {
|
|
197
218
|
// 水印字体颜色
|
|
198
219
|
type: String,
|
package/watermark.common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watermark.common.js","mappings":"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","sources":["webpack://vue3-watermark/webpack/bootstrap","webpack://vue3-watermark/webpack/runtime/define property getters","webpack://vue3-watermark/webpack/runtime/hasOwnProperty shorthand","webpack://vue3-watermark/webpack/runtime/make namespace object","webpack://vue3-watermark/webpack/runtime/publicPath","webpack://vue3-watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://vue3-watermark/external commonjs2 {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://vue3-watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://vue3-watermark/./src/packages/water-mark/index.vue","webpack://vue3-watermark/./src/packages/water-mark/index.vue?e80c","webpack://vue3-watermark/./src/packages/water-mark/index.vue?ba69","webpack://vue3-watermark/./src/packages/index.js","webpack://vue3-watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","var __WEBPACK_NAMESPACE_OBJECT__ = require(\"vue\");","import { computed } from 'vue';\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n // 测量当前文本的宽度\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n // 比较当前宽度与已记录的最大宽度\r\n if (currentWidth > maxWidth) {\r\n // 更新最大宽度和对应的最长文本\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n // 返回结果(包含最长文本和最大宽度,方便后续使用)\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n return computed(() => {\r\n // 创建一个 canvas\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n // 设置字体大小\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = props.waterFontWeight + ' ' + fontSize + 'px ' + props.waterFontFamily;\r\n const ctx = canvas.getContext('2d');\r\n // 获取文字宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n const canvasSize = Math.max(100, maxWidth) + props.waterGap * devicePixelRatio;\r\n canvas.width = canvasSize;\r\n canvas.height = canvasSize;\r\n ctx.translate(0, canvas.height / 2);\r\n // 旋转 45 度让文字变倾斜\r\n ctx.rotate((Math.PI / 180) * - props.waterRotate);\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.font = font;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor; // 阴影颜色:半透明深灰色(推荐RGBA)\r\n ctx.shadowOffsetX = props.shadowOffsetX; // 水平向右偏移 4px\r\n ctx.shadowOffsetY = props.shadowOffsetY; // 垂直向下偏移 4px\r\n ctx.shadowBlur = props.shadowBlur; // 阴影模糊半径 8px(边缘柔和)\r\n // 将文字画出来\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n ctx.fillText(item, 0, index * fontSize + index * 6);\r\n })\r\n } else {\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: canvasSize,\r\n styleSize: canvasSize / devicePixelRatio,\r\n };\r\n });\r\n}\r\n","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 20,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 30,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","export { default } from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"; export * from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["computed","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","canvas","document","createElement","devicePixelRatio","window","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterName","canvasSize","Math","max","waterGap","height","translate","rotate","PI","waterRotate","fillStyle","waterFontColor","textAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","forEach","item","index","fillText","base64","toDataURL","size","styleSize","onMounted","ref","__default__","name","__props","watermarkContainer","div","k","bg","value","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","watermark","components","install","Vue","component"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"watermark.common.js","mappings":"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","sources":["webpack://vue3-watermark/webpack/bootstrap","webpack://vue3-watermark/webpack/runtime/define property getters","webpack://vue3-watermark/webpack/runtime/hasOwnProperty shorthand","webpack://vue3-watermark/webpack/runtime/make namespace object","webpack://vue3-watermark/webpack/runtime/publicPath","webpack://vue3-watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://vue3-watermark/external commonjs2 {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://vue3-watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://vue3-watermark/./src/packages/water-mark/index.vue","webpack://vue3-watermark/./src/packages/water-mark/index.vue?e80c","webpack://vue3-watermark/./src/packages/water-mark/index.vue?ba69","webpack://vue3-watermark/./src/packages/index.js","webpack://vue3-watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","var __WEBPACK_NAMESPACE_OBJECT__ = require(\"vue\");","import { computed } from 'vue';\r\n\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n if (currentWidth > maxWidth) {\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n\r\n return computed(() => {\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = `${props.waterFontWeight} ${fontSize}px ${props.waterFontFamily}`;\r\n const ctx = canvas.getContext('2d');\r\n const waterGap = props.waterGap * devicePixelRatio; // 统一缓存适配后的间距\r\n\r\n // 第一步:先设置字体,测量文字最大宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n\r\n // 第二步:精准计算 Canvas 尺寸(平衡左右上下空间,无冗余浪费)\r\n // 核心:基于文字实际宽度+字体大小+间距,计算旋转后刚好容纳的画布尺寸\r\n const textTotalWidth = maxWidth; // 文字原始最大宽度\r\n const textTotalHeight = Array.isArray(props.waterName) \r\n ? (props.waterName.length - 1) * (fontSize + 6 * devicePixelRatio) + fontSize \r\n : fontSize; // 文字整体高度(多行文适配)\r\n // 画布基础尺寸:文字整体尺寸 + 双向间距(左右/上下各留一份gap,避免贴边)\r\n const baseCanvasSize = Math.max(100, Math.sqrt(textTotalWidth ** 2 + textTotalHeight ** 2)) + waterGap * 2;\r\n canvas.width = baseCanvasSize;\r\n canvas.height = baseCanvasSize;\r\n\r\n // 第三步:重置上下文,配置样式(保持原有功能不变)\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n ctx.font = font;\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.textAlign = props.waterTextAlign;\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor;\r\n ctx.shadowOffsetX = props.shadowOffsetX;\r\n ctx.shadowOffsetY = props.shadowOffsetY;\r\n ctx.shadowBlur = props.shadowBlur;\r\n\r\n // 第四步:核心修复——合理设置旋转中心+最小必要偏移(平衡左右上下)\r\n // 1. 旋转中心移至画布「左侧中间偏上」(而非中心),避免左右空间失衡\r\n // 2. 仅预留最小必要偏移(waterGap),既避免左上角截取,又不挤占右侧空间\r\n const safeOffset = waterGap; // 安全偏移量(最小必要,兼顾上下左右)\r\n ctx.translate(safeOffset, canvas.height / 2); // 水平仅偏移安全间距,垂直居中\r\n\r\n // 旋转水印(保持原有配置,无过度偏移)\r\n ctx.rotate((Math.PI / 180) * -props.waterRotate);\r\n\r\n // 第五步:绘制文字(基于安全偏移,无过度靠右,保证右侧完整)\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n // 垂直间距:适配设备像素比,保持原有排版逻辑\r\n const verticalGap = fontSize + 6 * devicePixelRatio;\r\n // 绘制起点:(0, index*verticalGap),无额外水平偏移,避免右侧溢出\r\n ctx.fillText(item, 0, index * verticalGap);\r\n });\r\n } else {\r\n // 单文本直接绘制,起点(0,0),基于已有的safeOffset保证左上角不截取\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n\r\n // 返回水印信息\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: baseCanvasSize,\r\n styleSize: baseCanvasSize / devicePixelRatio,\r\n };\r\n });\r\n}","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 100,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterTextAlign: {\r\n // 水印对齐方式\r\n type: String,\r\n default: \"left\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","export { default } from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"; export * from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["computed","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","canvas","document","createElement","devicePixelRatio","window","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterGap","waterName","textTotalWidth","textTotalHeight","baseCanvasSize","Math","max","sqrt","height","clearRect","fillStyle","waterFontColor","textAlign","waterTextAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","safeOffset","translate","rotate","PI","waterRotate","forEach","item","index","verticalGap","fillText","base64","toDataURL","size","styleSize","onMounted","ref","__default__","name","__props","watermarkContainer","div","k","bg","value","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","watermark","components","install","Vue","component"],"sourceRoot":""}
|
package/watermark.umd.js
CHANGED
|
@@ -138,62 +138,78 @@ function useWatermarkBg(props) {
|
|
|
138
138
|
// 遍历数组,逐个测量并比较宽度
|
|
139
139
|
for (let i = 1; i < textArr.length; i++) {
|
|
140
140
|
const currentText = textArr[i];
|
|
141
|
-
// 测量当前文本的宽度
|
|
142
141
|
const currentWidth = ctx.measureText(currentText).width;
|
|
143
|
-
|
|
144
|
-
// 比较当前宽度与已记录的最大宽度
|
|
145
142
|
if (currentWidth > maxWidth) {
|
|
146
|
-
// 更新最大宽度和对应的最长文本
|
|
147
143
|
maxWidth = currentWidth;
|
|
148
144
|
longestText = currentText;
|
|
149
145
|
}
|
|
150
146
|
}
|
|
151
|
-
|
|
152
|
-
// 返回结果(包含最长文本和最大宽度,方便后续使用)
|
|
153
147
|
return {
|
|
154
148
|
longestText,
|
|
155
149
|
maxWidth
|
|
156
150
|
};
|
|
157
151
|
}
|
|
158
152
|
return (0,external_commonjs_vue_commonjs2_vue_root_Vue_.computed)(() => {
|
|
159
|
-
// 创建一个 canvas
|
|
160
153
|
const canvas = document.createElement('canvas');
|
|
161
154
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
162
|
-
// 设置字体大小
|
|
163
155
|
const fontSize = props.waterFontSize * devicePixelRatio;
|
|
164
|
-
const font = props.waterFontWeight
|
|
156
|
+
const font = `${props.waterFontWeight} ${fontSize}px ${props.waterFontFamily}`;
|
|
165
157
|
const ctx = canvas.getContext('2d');
|
|
166
|
-
//
|
|
158
|
+
const waterGap = props.waterGap * devicePixelRatio; // 统一缓存适配后的间距
|
|
159
|
+
|
|
160
|
+
// 第一步:先设置字体,测量文字最大宽度
|
|
167
161
|
ctx.font = font;
|
|
168
162
|
const {
|
|
169
163
|
maxWidth
|
|
170
164
|
} = getLongestTextByWidth(props.waterName, ctx);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
|
|
166
|
+
// 第二步:精准计算 Canvas 尺寸(平衡左右上下空间,无冗余浪费)
|
|
167
|
+
// 核心:基于文字实际宽度+字体大小+间距,计算旋转后刚好容纳的画布尺寸
|
|
168
|
+
const textTotalWidth = maxWidth; // 文字原始最大宽度
|
|
169
|
+
const textTotalHeight = Array.isArray(props.waterName) ? (props.waterName.length - 1) * (fontSize + 6 * devicePixelRatio) + fontSize : fontSize; // 文字整体高度(多行文适配)
|
|
170
|
+
// 画布基础尺寸:文字整体尺寸 + 双向间距(左右/上下各留一份gap,避免贴边)
|
|
171
|
+
const baseCanvasSize = Math.max(100, Math.sqrt(textTotalWidth ** 2 + textTotalHeight ** 2)) + waterGap * 2;
|
|
172
|
+
canvas.width = baseCanvasSize;
|
|
173
|
+
canvas.height = baseCanvasSize;
|
|
174
|
+
|
|
175
|
+
// 第三步:重置上下文,配置样式(保持原有功能不变)
|
|
176
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
178
177
|
ctx.font = font;
|
|
179
|
-
ctx.
|
|
178
|
+
ctx.fillStyle = props.waterFontColor;
|
|
179
|
+
ctx.textAlign = props.waterTextAlign;
|
|
180
180
|
ctx.textBaseline = 'middle';
|
|
181
|
-
ctx.shadowColor = props.shadowColor;
|
|
182
|
-
ctx.shadowOffsetX = props.shadowOffsetX;
|
|
183
|
-
ctx.shadowOffsetY = props.shadowOffsetY;
|
|
184
|
-
ctx.shadowBlur = props.shadowBlur;
|
|
185
|
-
|
|
181
|
+
ctx.shadowColor = props.shadowColor;
|
|
182
|
+
ctx.shadowOffsetX = props.shadowOffsetX;
|
|
183
|
+
ctx.shadowOffsetY = props.shadowOffsetY;
|
|
184
|
+
ctx.shadowBlur = props.shadowBlur;
|
|
185
|
+
|
|
186
|
+
// 第四步:核心修复——合理设置旋转中心+最小必要偏移(平衡左右上下)
|
|
187
|
+
// 1. 旋转中心移至画布「左侧中间偏上」(而非中心),避免左右空间失衡
|
|
188
|
+
// 2. 仅预留最小必要偏移(waterGap),既避免左上角截取,又不挤占右侧空间
|
|
189
|
+
const safeOffset = waterGap; // 安全偏移量(最小必要,兼顾上下左右)
|
|
190
|
+
ctx.translate(safeOffset, canvas.height / 2); // 水平仅偏移安全间距,垂直居中
|
|
191
|
+
|
|
192
|
+
// 旋转水印(保持原有配置,无过度偏移)
|
|
193
|
+
ctx.rotate(Math.PI / 180 * -props.waterRotate);
|
|
194
|
+
|
|
195
|
+
// 第五步:绘制文字(基于安全偏移,无过度靠右,保证右侧完整)
|
|
186
196
|
if (Array.isArray(props.waterName)) {
|
|
187
197
|
props.waterName.forEach((item, index) => {
|
|
188
|
-
|
|
198
|
+
// 垂直间距:适配设备像素比,保持原有排版逻辑
|
|
199
|
+
const verticalGap = fontSize + 6 * devicePixelRatio;
|
|
200
|
+
// 绘制起点:(0, index*verticalGap),无额外水平偏移,避免右侧溢出
|
|
201
|
+
ctx.fillText(item, 0, index * verticalGap);
|
|
189
202
|
});
|
|
190
203
|
} else {
|
|
204
|
+
// 单文本直接绘制,起点(0,0),基于已有的safeOffset保证左上角不截取
|
|
191
205
|
ctx.fillText(props.waterName, 0, 0);
|
|
192
206
|
}
|
|
207
|
+
|
|
208
|
+
// 返回水印信息
|
|
193
209
|
return {
|
|
194
210
|
base64: canvas.toDataURL(),
|
|
195
|
-
size:
|
|
196
|
-
styleSize:
|
|
211
|
+
size: baseCanvasSize,
|
|
212
|
+
styleSize: baseCanvasSize / devicePixelRatio
|
|
197
213
|
};
|
|
198
214
|
});
|
|
199
215
|
}
|
|
@@ -225,18 +241,23 @@ const __default__ = {
|
|
|
225
241
|
waterGap: {
|
|
226
242
|
// 水印重复的间隔
|
|
227
243
|
type: Number,
|
|
228
|
-
default:
|
|
244
|
+
default: 100
|
|
229
245
|
},
|
|
230
246
|
waterRotate: {
|
|
231
247
|
// 水印倾斜
|
|
232
248
|
type: Number,
|
|
233
|
-
default:
|
|
249
|
+
default: 20
|
|
234
250
|
},
|
|
235
251
|
waterFontFamily: {
|
|
236
252
|
// 水印字体
|
|
237
253
|
type: String,
|
|
238
254
|
default: "Microsoft Yahei"
|
|
239
255
|
},
|
|
256
|
+
waterTextAlign: {
|
|
257
|
+
// 水印对齐方式
|
|
258
|
+
type: String,
|
|
259
|
+
default: "left"
|
|
260
|
+
},
|
|
240
261
|
waterFontColor: {
|
|
241
262
|
// 水印字体颜色
|
|
242
263
|
type: String,
|
package/watermark.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watermark.umd.js","mappings":"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","sources":["webpack://watermark/webpack/universalModuleDefinition","webpack://watermark/external umd {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://watermark/webpack/bootstrap","webpack://watermark/webpack/runtime/define property getters","webpack://watermark/webpack/runtime/hasOwnProperty shorthand","webpack://watermark/webpack/runtime/make namespace object","webpack://watermark/webpack/runtime/publicPath","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://watermark/./src/packages/water-mark/index.vue","webpack://watermark/./src/packages/water-mark/index.vue?e25b","webpack://watermark/./src/packages/water-mark/index.vue?ba69","webpack://watermark/./src/packages/index.js","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"vue\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"watermark\"] = factory(require(\"vue\"));\n\telse\n\t\troot[\"watermark\"] = factory(root[\"Vue\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__274__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__274__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","import { computed } from 'vue';\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n // 测量当前文本的宽度\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n // 比较当前宽度与已记录的最大宽度\r\n if (currentWidth > maxWidth) {\r\n // 更新最大宽度和对应的最长文本\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n // 返回结果(包含最长文本和最大宽度,方便后续使用)\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n return computed(() => {\r\n // 创建一个 canvas\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n // 设置字体大小\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = props.waterFontWeight + ' ' + fontSize + 'px ' + props.waterFontFamily;\r\n const ctx = canvas.getContext('2d');\r\n // 获取文字宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n const canvasSize = Math.max(100, maxWidth) + props.waterGap * devicePixelRatio;\r\n canvas.width = canvasSize;\r\n canvas.height = canvasSize;\r\n ctx.translate(0, canvas.height / 2);\r\n // 旋转 45 度让文字变倾斜\r\n ctx.rotate((Math.PI / 180) * - props.waterRotate);\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.font = font;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor; // 阴影颜色:半透明深灰色(推荐RGBA)\r\n ctx.shadowOffsetX = props.shadowOffsetX; // 水平向右偏移 4px\r\n ctx.shadowOffsetY = props.shadowOffsetY; // 垂直向下偏移 4px\r\n ctx.shadowBlur = props.shadowBlur; // 阴影模糊半径 8px(边缘柔和)\r\n // 将文字画出来\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n ctx.fillText(item, 0, index * fontSize + index * 6);\r\n })\r\n } else {\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: canvasSize,\r\n styleSize: canvasSize / devicePixelRatio,\r\n };\r\n });\r\n}\r\n","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 20,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 30,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","export { default } from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"; export * from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["computed","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","canvas","document","createElement","devicePixelRatio","window","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterName","canvasSize","Math","max","waterGap","height","translate","rotate","PI","waterRotate","fillStyle","waterFontColor","textAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","forEach","item","index","fillText","base64","toDataURL","size","styleSize","onMounted","ref","__default__","name","__props","watermarkContainer","div","k","bg","value","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","watermark","components","install","Vue","component"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"watermark.umd.js","mappings":"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","sources":["webpack://watermark/webpack/universalModuleDefinition","webpack://watermark/external umd {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://watermark/webpack/bootstrap","webpack://watermark/webpack/runtime/define property getters","webpack://watermark/webpack/runtime/hasOwnProperty shorthand","webpack://watermark/webpack/runtime/make namespace object","webpack://watermark/webpack/runtime/publicPath","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://watermark/./src/packages/water-mark/index.vue","webpack://watermark/./src/packages/water-mark/index.vue?e25b","webpack://watermark/./src/packages/water-mark/index.vue?ba69","webpack://watermark/./src/packages/index.js","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"vue\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"watermark\"] = factory(require(\"vue\"));\n\telse\n\t\troot[\"watermark\"] = factory(root[\"Vue\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__274__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__274__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","import { computed } from 'vue';\r\n\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n if (currentWidth > maxWidth) {\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n\r\n return computed(() => {\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = `${props.waterFontWeight} ${fontSize}px ${props.waterFontFamily}`;\r\n const ctx = canvas.getContext('2d');\r\n const waterGap = props.waterGap * devicePixelRatio; // 统一缓存适配后的间距\r\n\r\n // 第一步:先设置字体,测量文字最大宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n\r\n // 第二步:精准计算 Canvas 尺寸(平衡左右上下空间,无冗余浪费)\r\n // 核心:基于文字实际宽度+字体大小+间距,计算旋转后刚好容纳的画布尺寸\r\n const textTotalWidth = maxWidth; // 文字原始最大宽度\r\n const textTotalHeight = Array.isArray(props.waterName) \r\n ? (props.waterName.length - 1) * (fontSize + 6 * devicePixelRatio) + fontSize \r\n : fontSize; // 文字整体高度(多行文适配)\r\n // 画布基础尺寸:文字整体尺寸 + 双向间距(左右/上下各留一份gap,避免贴边)\r\n const baseCanvasSize = Math.max(100, Math.sqrt(textTotalWidth ** 2 + textTotalHeight ** 2)) + waterGap * 2;\r\n canvas.width = baseCanvasSize;\r\n canvas.height = baseCanvasSize;\r\n\r\n // 第三步:重置上下文,配置样式(保持原有功能不变)\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n ctx.font = font;\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.textAlign = props.waterTextAlign;\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor;\r\n ctx.shadowOffsetX = props.shadowOffsetX;\r\n ctx.shadowOffsetY = props.shadowOffsetY;\r\n ctx.shadowBlur = props.shadowBlur;\r\n\r\n // 第四步:核心修复——合理设置旋转中心+最小必要偏移(平衡左右上下)\r\n // 1. 旋转中心移至画布「左侧中间偏上」(而非中心),避免左右空间失衡\r\n // 2. 仅预留最小必要偏移(waterGap),既避免左上角截取,又不挤占右侧空间\r\n const safeOffset = waterGap; // 安全偏移量(最小必要,兼顾上下左右)\r\n ctx.translate(safeOffset, canvas.height / 2); // 水平仅偏移安全间距,垂直居中\r\n\r\n // 旋转水印(保持原有配置,无过度偏移)\r\n ctx.rotate((Math.PI / 180) * -props.waterRotate);\r\n\r\n // 第五步:绘制文字(基于安全偏移,无过度靠右,保证右侧完整)\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n // 垂直间距:适配设备像素比,保持原有排版逻辑\r\n const verticalGap = fontSize + 6 * devicePixelRatio;\r\n // 绘制起点:(0, index*verticalGap),无额外水平偏移,避免右侧溢出\r\n ctx.fillText(item, 0, index * verticalGap);\r\n });\r\n } else {\r\n // 单文本直接绘制,起点(0,0),基于已有的safeOffset保证左上角不截取\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n\r\n // 返回水印信息\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: baseCanvasSize,\r\n styleSize: baseCanvasSize / devicePixelRatio,\r\n };\r\n });\r\n}","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 100,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterTextAlign: {\r\n // 水印对齐方式\r\n type: String,\r\n default: \"left\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","export { default } from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"; export * from \"-!../../../node_modules/thread-loader/dist/cjs.js!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./index.vue?vue&type=script&setup=true&lang=js\"","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["computed","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","canvas","document","createElement","devicePixelRatio","window","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterGap","waterName","textTotalWidth","textTotalHeight","baseCanvasSize","Math","max","sqrt","height","clearRect","fillStyle","waterFontColor","textAlign","waterTextAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","safeOffset","translate","rotate","PI","waterRotate","forEach","item","index","verticalGap","fillText","base64","toDataURL","size","styleSize","onMounted","ref","__default__","name","__props","watermarkContainer","div","k","bg","value","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","watermark","components","install","Vue","component"],"sourceRoot":""}
|
package/watermark.umd.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("vue")):"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports["watermark"]=t(require("vue")):e["watermark"]=t(e["Vue"])})("undefined"!==typeof self?self:this,(function(e){return function(){"use strict";var t={274:function(t){t.exports=e}},r={};function a(e){var o=r[e];if(void 0!==o)return o.exports;var n=r[e]={exports:{}};return t[e](n,n.exports,a),n.exports}!function(){a.d=function(e,t){for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}}(),function(){a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}}(),function(){a.p=""}();var o={};return function(){if(a.r(o),a.d(o,{default:function(){return p}}),"undefined"!==typeof window){var e=window.document.currentScript,t=e&&e.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);t&&(a.p=t[1])}var r=a(274);function n(e){function t(e,t){if(!Array.isArray(e)||0===e.length)return{longestText:"",maxWidth:0};if("string"===typeof e)return{longestText:e,maxWidth:t.measureText(e).width};let r=e[0],a=t.measureText(r).width;for(let o=1;o<e.length;o++){const n=e[o],u=t.measureText(n).width;u>a&&(a=u,r=n)}return{longestText:r,maxWidth:a}}return(0,r.computed)((()=>{const r=document.createElement("canvas"),a=window.devicePixelRatio||1,o=e.waterFontSize*a,n
|
|
1
|
+
(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("vue")):"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports["watermark"]=t(require("vue")):e["watermark"]=t(e["Vue"])})("undefined"!==typeof self?self:this,(function(e){return function(){"use strict";var t={274:function(t){t.exports=e}},r={};function a(e){var o=r[e];if(void 0!==o)return o.exports;var n=r[e]={exports:{}};return t[e](n,n.exports,a),n.exports}!function(){a.d=function(e,t){for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}}(),function(){a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}}(),function(){a.p=""}();var o={};return function(){if(a.r(o),a.d(o,{default:function(){return p}}),"undefined"!==typeof window){var e=window.document.currentScript,t=e&&e.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);t&&(a.p=t[1])}var r=a(274);function n(e){function t(e,t){if(!Array.isArray(e)||0===e.length)return{longestText:"",maxWidth:0};if("string"===typeof e)return{longestText:e,maxWidth:t.measureText(e).width};let r=e[0],a=t.measureText(r).width;for(let o=1;o<e.length;o++){const n=e[o],u=t.measureText(n).width;u>a&&(a=u,r=n)}return{longestText:r,maxWidth:a}}return(0,r.computed)((()=>{const r=document.createElement("canvas"),a=window.devicePixelRatio||1,o=e.waterFontSize*a,n=`${e.waterFontWeight} ${o}px ${e.waterFontFamily}`,u=r.getContext("2d"),l=e.waterGap*a;u.font=n;const{maxWidth:i}=t(e.waterName,u),s=i,f=Array.isArray(e.waterName)?(e.waterName.length-1)*(o+6*a)+o:o,d=Math.max(100,Math.sqrt(s**2+f**2))+2*l;r.width=d,r.height=d,u.clearRect(0,0,r.width,r.height),u.font=n,u.fillStyle=e.waterFontColor,u.textAlign=e.waterTextAlign,u.textBaseline="middle",u.shadowColor=e.shadowColor,u.shadowOffsetX=e.shadowOffsetX,u.shadowOffsetY=e.shadowOffsetY,u.shadowBlur=e.shadowBlur;const c=l;return u.translate(c,r.height/2),u.rotate(Math.PI/180*-e.waterRotate),Array.isArray(e.waterName)?e.waterName.forEach(((e,t)=>{const r=o+6*a;u.fillText(e,0,t*r)})):u.fillText(e.waterName,0,0),{base64:r.toDataURL(),size:d,styleSize:d/a}}))}const u={name:"watermark"};var l=Object.assign(u,{props:{waterName:{type:[String,Array],required:!0,default:"watermark"},waterFontSize:{type:Number,default:20},waterFontWeight:{type:Number,default:700},waterGap:{type:Number,default:100},waterRotate:{type:Number,default:20},waterFontFamily:{type:String,default:"Microsoft Yahei"},waterTextAlign:{type:String,default:"left"},waterFontColor:{type:String,default:"rgba(255, 255, 255, 1)"},shadowColor:{type:String,default:"rgba(61, 61, 61, 0.25)"},shadowOffsetX:{type:Number,default:1.5},shadowOffsetY:{type:Number,default:1.5},shadowBlur:{type:Number,default:0}},setup(e){const t=e,a=(0,r.ref)(null),o=(0,r.ref)(null),u=(0,r.ref)(null),l=n(t),{base64:i,styleSize:s}=l.value;(0,r.onMounted)((()=>{f(),u.value=new MutationObserver((e=>{for(const t of e){for(const e of t.removedNodes)if(e===o.value)return o.value.remove(),void f();if(t.target===o.value)return o.value.remove(),void f()}})),u.value.observe(a.value,{childList:!0,attributes:!0,subtree:!0})}));const f=()=>{o.value=document.createElement("div"),o.value.style.backgroundImage=`url(${i})`,o.value.style.inset=0,o.value.style.zIndex=9999,o.value.style.position="absolute",o.value.style.backgroundRepeat="repeat",o.value.style.backgroundSize=`${s}px ${s}px`,o.value.style.pointerEvents="none",a.value.appendChild(o.value)};return(e,t)=>((0,r.openBlock)(),(0,r.createElementBlock)("div",{class:"watermark-container",ref_key:"watermarkContainer",ref:a},[(0,r.renderSlot)(e.$slots,"default")],512))}});const i=l;var s=i;const f=[s],d=function(e){f.forEach((t=>{e.component(t.name,t)}))};var c=d,p=c}(),o}()}));
|
|
2
2
|
//# sourceMappingURL=watermark.umd.min.js.map
|
package/watermark.umd.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watermark.umd.min.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,kBAAZC,SAA0C,kBAAXC,OACxCA,OAAOD,QAAUD,EAAQG,QAAQ,QACR,oBAAXC,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIJ,GACe,kBAAZC,QACdA,QAAQ,aAAeD,EAAQG,QAAQ,QAEvCJ,EAAK,aAAeC,EAAQD,EAAK,OAClC,EATD,CASoB,qBAATO,KAAuBA,KAAOC,MAAO,SAASC,GACzD,O,+CCVAN,EAAOD,QAAUO,C,GCCbC,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaX,QAGrB,IAAIC,EAASO,EAAyBE,GAAY,CAGjDV,QAAS,CAAC,GAOX,OAHAa,EAAoBH,GAAUT,EAAQA,EAAOD,QAASS,GAG/CR,EAAOD,OACf,E,WCrBAS,EAAoBK,EAAI,SAASd,EAASe,GACzC,IAAI,IAAIC,KAAOD,EACXN,EAAoBQ,EAAEF,EAAYC,KAASP,EAAoBQ,EAAEjB,EAASgB,IAC5EE,OAAOC,eAAenB,EAASgB,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,IAG3E,C,eCPAP,EAAoBQ,EAAI,SAASK,EAAKC,GAAQ,OAAOL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,EAAO,C,eCCtGd,EAAoBkB,EAAI,SAAS3B,GACX,qBAAX4B,QAA0BA,OAAOC,aAC1CX,OAAOC,eAAenB,EAAS4B,OAAOC,YAAa,CAAEC,MAAO,WAE7DZ,OAAOC,eAAenB,EAAS,aAAc,CAAE8B,OAAO,GACvD,C,eCNArB,EAAoBsB,EAAI,E,+BCGxB,G,6CAAsB,qBAAXC,OAAwB,CACjC,IAAIC,EAAgBD,OAAOE,SAASD,cAWhCE,EAAMF,GAAiBA,EAAcE,IAAIC,MAAM,2BAC/CD,IACF,IAA0BA,EAAI,GAElC,CAGA,I,SCrBe,SAASE,EAAgBC,GAEpC,SAASC,EAAsBC,EAASC,GAEtC,IAAKC,MAAMC,QAAQH,IAA+B,IAAnBA,EAAQI,OACnC,MAAO,CACHC,YAAa,GACbC,SAAU,GAKlB,GAAuB,kBAAZN,EACP,MAAO,CACHK,YAAaL,EACbM,SAAUL,EAAIM,YAAYP,GAASQ,OAK3C,IAAIH,EAAcL,EAAQ,GACtBM,EAAWL,EAAIM,YAAYF,GAAaG,MAG5C,IAAK,IAAIC,EAAI,EAAGA,EAAIT,EAAQI,OAAQK,IAAK,CACrC,MAAMC,EAAcV,EAAQS,GAEtBE,EAAeV,EAAIM,YAAYG,GAAaF,MAG9CG,EAAeL,IAEfA,EAAWK,EACXN,EAAcK,EAEtB,CAGA,MAAO,CACHL,cACAC,WAER,CACA,OAAOM,EAAAA,EAAAA,WAAS,KAEd,MAAMC,EAASnB,SAASoB,cAAc,UAChCC,EAAmBvB,OAAOuB,kBAAoB,EAE9CC,EAAWlB,EAAMmB,cAAgBF,EACjCG,EAAOpB,EAAMqB,gBAAkB,IAAMH,EAAW,MAAQlB,EAAMsB,gBAC9DnB,EAAMY,EAAOQ,WAAW,MAE9BpB,EAAIiB,KAAOA,EACX,MAAM,SAAEZ,GAAaP,EAAsBD,EAAMwB,UAAWrB,GACtDsB,EAAaC,KAAKC,IAAI,IAAKnB,GAAYR,EAAM4B,SAAWX,EAsB9D,OArBAF,EAAOL,MAAQe,EACfV,EAAOc,OAASJ,EAChBtB,EAAI2B,UAAU,EAAGf,EAAOc,OAAS,GAEjC1B,EAAI4B,OAAQL,KAAKM,GAAK,KAAShC,EAAMiC,aACrC9B,EAAI+B,UAAYlC,EAAMmC,eACtBhC,EAAIiB,KAAOA,EACXjB,EAAIiC,UAAY,OAChBjC,EAAIkC,aAAe,SACnBlC,EAAImC,YAActC,EAAMsC,YACxBnC,EAAIoC,cAAgBvC,EAAMuC,cAC1BpC,EAAIqC,cAAgBxC,EAAMwC,cAC1BrC,EAAIsC,WAAazC,EAAMyC,WAEnBrC,MAAMC,QAAQL,EAAMwB,WACtBxB,EAAMwB,UAAUkB,SAAQ,CAACC,EAAMC,KAC7BzC,EAAI0C,SAASF,EAAM,EAAGC,EAAQ1B,EAAmB,EAAR0B,EAAU,IAGrDzC,EAAI0C,SAAS7C,EAAMwB,UAAW,EAAG,GAE5B,CACLsB,OAAQ/B,EAAOgC,YACfC,KAAMvB,EACNwB,UAAWxB,EAAaR,EACzB,GAEL,CC7EA,MAAAiC,EAAe,CACbC,KAAM,a,oiBAOR,MAAMnD,EAAQoD,EA2DRC,GAAqBC,EAAAA,EAAAA,KAAI,MACzBC,GAAMD,EAAAA,EAAAA,KAAI,MACVE,GAAIF,EAAAA,EAAAA,KAAI,MACRG,EAAK1D,EAAeC,IACpB,OAAE8C,EAAM,UAAEG,GAAcQ,EAAGjE,OAEjCkE,EAAAA,EAAAA,YAAU,KACRC,IAGAH,EAAEhE,MAAQ,IAAIoE,kBAAkBC,IAC9B,IAAK,MAAMC,KAAUD,EAAS,CAC5B,IAAK,MAAME,KAAOD,EAAOE,aACvB,GAAID,IAAQR,EAAI/D,MAGd,OAFA+D,EAAI/D,MAAMyE,cACVN,IAIJ,GAAIG,EAAOI,SAAWX,EAAI/D,MAGxB,OAFA+D,EAAI/D,MAAMyE,cACVN,GAGJ,KAEFH,EAAEhE,MAAM2E,QAAQd,EAAmB7D,MAAO,CACxC4E,WAAW,EACXC,YAAY,EACZC,SAAS,GACT,IAEJ,MAAMX,EAASA,KACbJ,EAAI/D,MAAQI,SAASoB,cAAc,OACnCuC,EAAI/D,MAAM+E,MAAMC,gBAAmB,OAAM1B,KACzCS,EAAI/D,MAAM+E,MAAME,MAAQ,EACxBlB,EAAI/D,MAAM+E,MAAMG,OAAS,KACzBnB,EAAI/D,MAAM+E,MAAMI,SAAW,WAC3BpB,EAAI/D,MAAM+E,MAAMK,iBAAmB,SACnCrB,EAAI/D,MAAM+E,MAAMM,eAAkB,GAAE5B,OAAeA,MACnDM,EAAI/D,MAAM+E,MAAMO,cAAgB,OAChCzB,EAAmB7D,MAAMuF,YAAYxB,EAAI/D,MAAM,E,gLC/GjD,MAAMwF,EAAc,EAEpB,QCHA,MAAMC,EAAa,CAAEC,GAGfC,EAAU,SAAUC,GACtBH,EAAWvC,SAASc,IAChB4B,EAAIC,UAAU7B,EAAEL,KAAMK,EAAE,GAEhC,EAEA,QCTA,G","sources":["webpack://watermark/webpack/universalModuleDefinition","webpack://watermark/external umd {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://watermark/webpack/bootstrap","webpack://watermark/webpack/runtime/define property getters","webpack://watermark/webpack/runtime/hasOwnProperty shorthand","webpack://watermark/webpack/runtime/make namespace object","webpack://watermark/webpack/runtime/publicPath","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://watermark/./src/packages/water-mark/index.vue","webpack://watermark/./src/packages/water-mark/index.vue?ba69","webpack://watermark/./src/packages/index.js","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"vue\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"watermark\"] = factory(require(\"vue\"));\n\telse\n\t\troot[\"watermark\"] = factory(root[\"Vue\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__274__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__274__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","import { computed } from 'vue';\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n // 测量当前文本的宽度\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n // 比较当前宽度与已记录的最大宽度\r\n if (currentWidth > maxWidth) {\r\n // 更新最大宽度和对应的最长文本\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n // 返回结果(包含最长文本和最大宽度,方便后续使用)\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n return computed(() => {\r\n // 创建一个 canvas\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n // 设置字体大小\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = props.waterFontWeight + ' ' + fontSize + 'px ' + props.waterFontFamily;\r\n const ctx = canvas.getContext('2d');\r\n // 获取文字宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n const canvasSize = Math.max(100, maxWidth) + props.waterGap * devicePixelRatio;\r\n canvas.width = canvasSize;\r\n canvas.height = canvasSize;\r\n ctx.translate(0, canvas.height / 2);\r\n // 旋转 45 度让文字变倾斜\r\n ctx.rotate((Math.PI / 180) * - props.waterRotate);\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.font = font;\r\n ctx.textAlign = 'left';\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor; // 阴影颜色:半透明深灰色(推荐RGBA)\r\n ctx.shadowOffsetX = props.shadowOffsetX; // 水平向右偏移 4px\r\n ctx.shadowOffsetY = props.shadowOffsetY; // 垂直向下偏移 4px\r\n ctx.shadowBlur = props.shadowBlur; // 阴影模糊半径 8px(边缘柔和)\r\n // 将文字画出来\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n ctx.fillText(item, 0, index * fontSize + index * 6);\r\n })\r\n } else {\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: canvasSize,\r\n styleSize: canvasSize / devicePixelRatio,\r\n };\r\n });\r\n}\r\n","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 20,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 30,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["root","factory","exports","module","require","define","amd","self","this","__WEBPACK_EXTERNAL_MODULE__274__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","p","window","currentScript","document","src","match","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","computed","canvas","createElement","devicePixelRatio","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterName","canvasSize","Math","max","waterGap","height","translate","rotate","PI","waterRotate","fillStyle","waterFontColor","textAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","forEach","item","index","fillText","base64","toDataURL","size","styleSize","__default__","name","__props","watermarkContainer","ref","div","k","bg","onMounted","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","__exports__","components","watermark","install","Vue","component"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"watermark.umd.min.js","mappings":"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","sources":["webpack://watermark/webpack/universalModuleDefinition","webpack://watermark/external umd {\"commonjs\":\"vue\",\"commonjs2\":\"vue\",\"root\":\"Vue\"}","webpack://watermark/webpack/bootstrap","webpack://watermark/webpack/runtime/define property getters","webpack://watermark/webpack/runtime/hasOwnProperty shorthand","webpack://watermark/webpack/runtime/make namespace object","webpack://watermark/webpack/runtime/publicPath","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://watermark/./src/packages/water-mark/useWatermarkBg.js","webpack://watermark/./src/packages/water-mark/index.vue","webpack://watermark/./src/packages/water-mark/index.vue?ba69","webpack://watermark/./src/packages/index.js","webpack://watermark/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"vue\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"watermark\"] = factory(require(\"vue\"));\n\telse\n\t\troot[\"watermark\"] = factory(root[\"Vue\"]);\n})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__274__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__274__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.p = \"\";","/* eslint-disable no-var */\n// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","import { computed } from 'vue';\r\n\r\nexport default function useWatermarkBg (props) {\r\n // 获取数组中宽度最长的文本和对应的最大宽度\r\n function getLongestTextByWidth(textArr, ctx) {\r\n // 边界处理:空数组直接返回空结果\r\n if (!Array.isArray(textArr) || textArr.length === 0) {\r\n return {\r\n longestText: '',\r\n maxWidth: 0\r\n };\r\n }\r\n\r\n // 字符串直接返回宽度\r\n if (typeof textArr === 'string') {\r\n return {\r\n longestText: textArr,\r\n maxWidth: ctx.measureText(textArr).width\r\n };\r\n }\r\n\r\n // 初始化变量:记录最长文本和最大宽度\r\n let longestText = textArr[0];\r\n let maxWidth = ctx.measureText(longestText).width;\r\n\r\n // 遍历数组,逐个测量并比较宽度\r\n for (let i = 1; i < textArr.length; i++) {\r\n const currentText = textArr[i];\r\n const currentWidth = ctx.measureText(currentText).width;\r\n\r\n if (currentWidth > maxWidth) {\r\n maxWidth = currentWidth;\r\n longestText = currentText;\r\n }\r\n }\r\n\r\n return {\r\n longestText,\r\n maxWidth\r\n };\r\n }\r\n\r\n return computed(() => {\r\n const canvas = document.createElement('canvas');\r\n const devicePixelRatio = window.devicePixelRatio || 1;\r\n const fontSize = props.waterFontSize * devicePixelRatio;\r\n const font = `${props.waterFontWeight} ${fontSize}px ${props.waterFontFamily}`;\r\n const ctx = canvas.getContext('2d');\r\n const waterGap = props.waterGap * devicePixelRatio; // 统一缓存适配后的间距\r\n\r\n // 第一步:先设置字体,测量文字最大宽度\r\n ctx.font = font;\r\n const { maxWidth } = getLongestTextByWidth(props.waterName, ctx);\r\n\r\n // 第二步:精准计算 Canvas 尺寸(平衡左右上下空间,无冗余浪费)\r\n // 核心:基于文字实际宽度+字体大小+间距,计算旋转后刚好容纳的画布尺寸\r\n const textTotalWidth = maxWidth; // 文字原始最大宽度\r\n const textTotalHeight = Array.isArray(props.waterName) \r\n ? (props.waterName.length - 1) * (fontSize + 6 * devicePixelRatio) + fontSize \r\n : fontSize; // 文字整体高度(多行文适配)\r\n // 画布基础尺寸:文字整体尺寸 + 双向间距(左右/上下各留一份gap,避免贴边)\r\n const baseCanvasSize = Math.max(100, Math.sqrt(textTotalWidth ** 2 + textTotalHeight ** 2)) + waterGap * 2;\r\n canvas.width = baseCanvasSize;\r\n canvas.height = baseCanvasSize;\r\n\r\n // 第三步:重置上下文,配置样式(保持原有功能不变)\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n ctx.font = font;\r\n ctx.fillStyle = props.waterFontColor;\r\n ctx.textAlign = props.waterTextAlign;\r\n ctx.textBaseline = 'middle';\r\n ctx.shadowColor = props.shadowColor;\r\n ctx.shadowOffsetX = props.shadowOffsetX;\r\n ctx.shadowOffsetY = props.shadowOffsetY;\r\n ctx.shadowBlur = props.shadowBlur;\r\n\r\n // 第四步:核心修复——合理设置旋转中心+最小必要偏移(平衡左右上下)\r\n // 1. 旋转中心移至画布「左侧中间偏上」(而非中心),避免左右空间失衡\r\n // 2. 仅预留最小必要偏移(waterGap),既避免左上角截取,又不挤占右侧空间\r\n const safeOffset = waterGap; // 安全偏移量(最小必要,兼顾上下左右)\r\n ctx.translate(safeOffset, canvas.height / 2); // 水平仅偏移安全间距,垂直居中\r\n\r\n // 旋转水印(保持原有配置,无过度偏移)\r\n ctx.rotate((Math.PI / 180) * -props.waterRotate);\r\n\r\n // 第五步:绘制文字(基于安全偏移,无过度靠右,保证右侧完整)\r\n if (Array.isArray(props.waterName)) {\r\n props.waterName.forEach((item, index) => {\r\n // 垂直间距:适配设备像素比,保持原有排版逻辑\r\n const verticalGap = fontSize + 6 * devicePixelRatio;\r\n // 绘制起点:(0, index*verticalGap),无额外水平偏移,避免右侧溢出\r\n ctx.fillText(item, 0, index * verticalGap);\r\n });\r\n } else {\r\n // 单文本直接绘制,起点(0,0),基于已有的safeOffset保证左上角不截取\r\n ctx.fillText(props.waterName, 0, 0);\r\n }\r\n\r\n // 返回水印信息\r\n return {\r\n base64: canvas.toDataURL(),\r\n size: baseCanvasSize,\r\n styleSize: baseCanvasSize / devicePixelRatio,\r\n };\r\n });\r\n}","<template>\r\n <div class=\"watermark-container\" ref=\"watermarkContainer\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: 'watermark',\r\n}\r\n</script>\r\n\r\n<script setup>\r\nimport { defineProps, onMounted, ref } from \"vue\";\r\nimport useWatermarkBg from \"./useWatermarkBg.js\";\r\nconst props = defineProps({\r\n waterName: {\r\n // 传入水印的文本\r\n type: [String, Array],\r\n required: true,\r\n default: \"watermark\",\r\n },\r\n waterFontSize: {\r\n // 字体的大小\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontWeight: {\r\n // 字体的粗细\r\n type: Number,\r\n default: 700,\r\n },\r\n waterGap: {\r\n // 水印重复的间隔\r\n type: Number,\r\n default: 100,\r\n },\r\n waterRotate: {\r\n // 水印倾斜\r\n type: Number,\r\n default: 20,\r\n },\r\n waterFontFamily: {\r\n // 水印字体\r\n type: String,\r\n default: \"Microsoft Yahei\",\r\n },\r\n waterTextAlign: {\r\n // 水印对齐方式\r\n type: String,\r\n default: \"left\",\r\n },\r\n waterFontColor: {\r\n // 水印字体颜色\r\n type: String,\r\n default: \"rgba(255, 255, 255, 1)\", // rgba(255, 255, 255, 0.2)\r\n },\r\n shadowColor: {\r\n // 阴影颜色\r\n type: String,\r\n default: \"rgba(61, 61, 61, 0.25)\",\r\n },\r\n shadowOffsetX: {\r\n // 阴影水平偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowOffsetY: {\r\n // 阴影垂直偏移\r\n type: Number,\r\n default: 1.5,\r\n },\r\n shadowBlur: {\r\n // 阴影模糊半径\r\n type: Number,\r\n default: 0,\r\n },\r\n});\r\n\r\nconst watermarkContainer = ref(null); // 挂载的dom节点\r\nconst div = ref(null); // 水印节点\r\nconst k = ref(null); // 监听器\r\nconst bg = useWatermarkBg(props); // 水印参数\r\nconst { base64, styleSize } = bg.value;\r\n\r\nonMounted(() => {\r\n addDom();\r\n\r\n // 添加dom监控器\r\n k.value = new MutationObserver((records) => {\r\n for (const record of records) {\r\n for (const dom of record.removedNodes) {\r\n if (dom === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n if (record.target === div.value) {\r\n div.value.remove();\r\n addDom();\r\n return;\r\n }\r\n }\r\n });\r\n k.value.observe(watermarkContainer.value, {\r\n childList: true,\r\n attributes: true,\r\n subtree: true,\r\n });\r\n});\r\nconst addDom = () => {\r\n div.value = document.createElement(\"div\");\r\n div.value.style.backgroundImage = `url(${base64})`;\r\n div.value.style.inset = 0;\r\n div.value.style.zIndex = 9999;\r\n div.value.style.position = \"absolute\";\r\n div.value.style.backgroundRepeat = \"repeat\";\r\n div.value.style.backgroundSize = `${styleSize}px ${styleSize}px`;\r\n div.value.style.pointerEvents = \"none\";\r\n watermarkContainer.value.appendChild(div.value);\r\n};\r\n</script>\r\n","import script from \"./index.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./index.vue?vue&type=script&setup=true&lang=js\"\n\nconst __exports__ = script;\n\nexport default __exports__","import watermark from './water-mark/index.vue';\r\n\r\nconst components = [ watermark ]\r\n\r\n// 注册组件\r\nconst install = function (Vue) {\r\n components.forEach((k) => {\r\n Vue.component(k.name, k)\r\n })\r\n}\r\n\r\nexport default install;","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"names":["root","factory","exports","module","require","define","amd","self","this","__WEBPACK_EXTERNAL_MODULE__274__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","p","window","currentScript","document","src","match","useWatermarkBg","props","getLongestTextByWidth","textArr","ctx","Array","isArray","length","longestText","maxWidth","measureText","width","i","currentText","currentWidth","computed","canvas","createElement","devicePixelRatio","fontSize","waterFontSize","font","waterFontWeight","waterFontFamily","getContext","waterGap","waterName","textTotalWidth","textTotalHeight","baseCanvasSize","Math","max","sqrt","height","clearRect","fillStyle","waterFontColor","textAlign","waterTextAlign","textBaseline","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","safeOffset","translate","rotate","PI","waterRotate","forEach","item","index","verticalGap","fillText","base64","toDataURL","size","styleSize","__default__","name","__props","watermarkContainer","ref","div","k","bg","onMounted","addDom","MutationObserver","records","record","dom","removedNodes","remove","target","observe","childList","attributes","subtree","style","backgroundImage","inset","zIndex","position","backgroundRepeat","backgroundSize","pointerEvents","appendChild","__exports__","components","watermark","install","Vue","component"],"sourceRoot":""}
|