改造svg全屏水印
支持防删
支持动态配置
代码备忘
watermarkSvg.js
/*eslint-disable*/
export function watermark(settings = {}, listening) {
// 默认设置
var defaultSettings = {
watermark_txt: 'text',
watermark_x: 20, // 水印起始位置x轴坐标
watermark_y: 20, // 水印起始位置Y轴坐标
watermark_rows: 20, // 水印行数
watermark_cols: 20, // 水印列数
watermark_x_space: 50, // 水印x轴间隔
watermark_y_space: 50, // 水印y轴间隔
watermark_color: '#ffffff', // 水印字体颜色
watermark_alpha: 0.16, // 水印透明度
watermark_fontsize: '16px', // 水印字体大小
watermark_font: '黑体', // 水印字体
watermark_width: 210, // 水印宽度
watermark_height: 80, // 水印长度
watermark_angle: -25, // 水印倾斜度数,
clear:false, // 清除水印
...settings
};
var svgXMLLink = 'http://www.w3.org/2000/svg'
var oTempSvg = document.createElementNS(svgXMLLink, "svg"); // 创建带有标准svg命名空间的节点
const box = getBBox({
...defaultSettings,
fontSize: defaultSettings.watermark_fontsize,
text: defaultSettings.watermark_txt
})
if (defaultSettings.watermark_angle < 0 && !defaultSettings.watermark_y_changed) {
defaultSettings.watermark_y += box.height
defaultSettings.watermark_y_changed = true;
}
// 获取页面最大宽度
var page_width = Math.max(
document.body.scrollWidth,
document.body.clientWidth
);
// 获取页面最大高度
var page_height =
Math.max(document.body.scrollHeight, document.body.clientHeight);// + 450
page_height = Math.max(page_height, window.innerHeight);
// 如果将水印列数设置为0,或水印列数设置过大,超过页面最大宽度,则重新计算水印列数和水印x轴间隔
oTempSvg.setAttribute('width', page_width)
oTempSvg.setAttribute('height', page_height)
oTempSvg.setAttribute("viewBox", `0 0 ${page_width} ${page_height}`);
defaultSettings.watermark_cols = Math.ceil(
(page_width -
- defaultSettings.watermark_x) /
(box.width + defaultSettings.watermark_x_space)
);
// 如果将水印行数设置为0,或水印行数设置过大,超过页面最大长度,则重新计算水印行数和水印y轴间隔
defaultSettings.watermark_rows = Math.ceil(
(page_height -
defaultSettings.watermark_y) /
(box.height + defaultSettings.watermark_y_space)
) + 1;
var x;
var y;
for (var i = 0; i < defaultSettings.watermark_rows; i++) {
y =
defaultSettings.watermark_y +
(defaultSettings.watermark_y_space + box.height) *
i;
//偶数行偏移半个容器宽度
var offsetX = (i % 2) * ((box.width + defaultSettings.watermark_x_space) / 2);
for (var j = 0; j < defaultSettings.watermark_cols; j++) {
if (offsetX && j == defaultSettings.watermark_cols - 1) {
//有偏移的行最后一列不展示
continue;
}
x =
offsetX + defaultSettings.watermark_x +
(box.width + defaultSettings.watermark_x_space) *
j;
var mask_div = document.createElementNS(svgXMLLink, 'text');
mask_div.id = 'mask_div' + i + j;
mask_div.setAttribute("id", 'mask_div' + i + j);
mask_div.innerHTML = defaultSettings.watermark_txt;
// 设置水印div倾斜显示
mask_div.setAttribute("transform", `translate(${x},${y}) rotate(${defaultSettings.watermark_angle})`);
mask_div.style.visibility = '';
// 让水印不遮挡页面的点击事件
mask_div.style.pointerEvents = 'none';
mask_div.style.opacity = defaultSettings.watermark_alpha;
mask_div.style.fontSize = defaultSettings.watermark_fontsize;
// mask_div.style.fontFamily = defaultSettings.watermark_font;
mask_div.setAttribute("fill", defaultSettings.watermark_color);
oTempSvg.appendChild(mask_div);
}
}
document.body.appendChild(oTempSvg)
var canvas = document.createElement("canvas");
var bbox = oTempSvg.getBBox();
canvas.width = bbox.width;
canvas.height = bbox.height;
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, bbox.width, bbox.height);
var data = (new XMLSerializer()).serializeToString(oTempSvg);
document.body.removeChild(oTempSvg)
const base64 = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(data)))}`;
defaultSettings = {
...defaultSettings,
base64
}
renderWarterMark(defaultSettings, listening)
// };
// listenNodesChange(maskDivsContainerData, settings, listening,)
}
function renderWarterMark(settings, listening) {
var maskDivContaniner = document.querySelector('#waterMarkContainer')
maskDivContaniner && maskDivContaniner.parentNode.removeChild(maskDivContaniner)
let waterMarkContainer = document.createElement('div')
waterMarkContainer.id = 'waterMarkContainer'
waterMarkContainer.style.background = `url(${settings.base64}) no-repeat left top`;
waterMarkContainer.style.position = `fixed`;
waterMarkContainer.style.top = `0`;
waterMarkContainer.style.left = `0`;
waterMarkContainer.style.zIndex = `9999`;
waterMarkContainer.style.width = `100%`;
waterMarkContainer.style.height = `100%`;
waterMarkContainer.style.pointerEvents = 'none';
document.body.appendChild(waterMarkContainer)
listenNodesChange(settings)
}
function observe(el, options, callback) {
let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
let ob = new MutationObserver(callback)
ob.observe(el, options)
return ob;
}
let obList = []; //已经启动的监听列表
export function listenNodesChange(settings) {
// 清除水印
if (settings.clear) {
obList.forEach(ob => {
ob.value && ob.value.disconnect && ob.value.disconnect();
ob = null;
})
obList = []
const dom = document.querySelector('#waterMarkContainer');
document.body.removeChild(dom)
return;
}
if (!obList.find((item) => item.name === "waterMark")) {
// 监听水印自身属性变化 - 防修改 style
const $waterMarkContainer = document.querySelector("#waterMarkContainer");
let waterMarkOb = observe(
$waterMarkContainer,
{
attributes: true,
characterData: true,
characterDataOldValue: true,
},
function (records, _self) {
const index = obList.findIndex((item) => item.name === "waterMark");
obList.splice(index, 1);
waterMarkOb.disconnect();
waterMarkOb = null;
watermark(settings);
}
);
obList.push({ name: "waterMark", value: waterMarkOb });
}
if (!obList.find((item) => item.name === "body")) {
//监听body - 防止水印自身被删除
const $body = document.body;
let bodyOb = observe(
$body,
{
childList: true,
},
function (records, _self) {
const $watermark = document.querySelector("#waterMarkContainer");
if (!$watermark) {
// 被删后重置所有监听
obList.forEach((item) => {
item.value && item.value.disconnect && item.value.disconnect();
item.value = null;
});
obList = [];
watermark(settings);
}
}
);
obList.push({ name: "body", value: bodyOb });
}
}
function getBBox(settings = {
fontSize: 16,
text: ''
}) {
var svgXMLLink = 'http://www.w3.org/2000/svg'
var oTempSvg = document.createElementNS(svgXMLLink, "svg"); // 创建带有标准svg命名空间的节点
oTempSvg.style = `position:fixed;z-index:-1`;
var data = document.createTextNode(settings.text);
var svgElement = document.createElementNS(svgXMLLink, "text");
svgElement.appendChild(data);
svgElement.setAttribute('font-size', settings.fontSize)
svgElement.setAttribute('transform', `rotate(${settings.watermark_angle})`)
document.body.appendChild(oTempSvg)
oTempSvg.appendChild(svgElement);
const result = svgElement.getBoundingClientRect()
document.body.removeChild(oTempSvg)
return {
width: Math.ceil(result.width),
height: Math.ceil(result.height)
};
}
页面引用
import { watermark } from '@/utils/watermarkSvg';
export default {
...
computed: {
// 水印配置
watermarkOptions() {
return {
watermark_color: '#c1c1c1',
watermark_txt: `moment().format('YYYY-MM-DD HH:mm:ss')`,
watermark_x_space: 20, // 水印x轴间隔
watermark_y_space: 20, // 水印y轴间隔
watermark_angle: -30,
};
}
},
mounted() {
watermark(this.watermarkOptions);
let resizing = false;
window.addEventListener('resize', () => {
if (!resizing) {
resizing = true;
watermark(this.watermarkOptions);
setTimeout(() => {
resizing = false;
}, 100);
}
});
},
beforeDestroy() {
watermark({
...this.watermarkOptions,
clear: true,
});
},