编写创建水印函数
// 获取水印图片
const getWaterMarker = (needWatermark: boolean, content: string) => {
if (!needWatermark) return {};
const can = document.createElement('canvas');
can.width = 200;
can.height = 140;
const cans = can.getContext('2d');
if (!cans) return {};
cans.rotate((-20 * Math.PI) / 180); // 旋转角度
cans.font =
'12px PingFangSC-Light,Microsoft YaHei,Helvetica Neue,Helvetica,Roboto,Tahoma,Arial'; // 设置字体大小
cans.fillStyle = 'rgb(88, 87, 86, 0.1)'; // 设置填充绘画的颜色、渐变或者模式
cans.textAlign = 'left'; // 设置文本内容的当前对齐方式
cans.textBaseline = 'middle'; // 设置在绘制文本时使用的当前文本基线
cans.fillText(content, can.width / 8 - 25, can.height / 2); // 输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置
// 将 canvas 转化为图片并且设置为背景
const style: CSSProperties = {
backgroundImage: `url(${can.toDataURL('image/png')})`,
backgroundRepeat: 'repeat',
};
return style;
}
// 手写水印
const createWatermark = (needWatermark?: boolean, parent?: HTMLElement) => {
if (!needWatermark) return;
const parentElement = parent || document.body;
const appWaterMarkNode = document.getElementById('__app-waterMark__');
if (appWaterMarkNode && parentElement.contains(appWaterMarkNode)){
parentElement.removeChild(appWaterMarkNode)
}
const styles = getWaterMarker(true, '水印文本');
if (!styles?.backgroundImage) return;
const watermarkDiv = document.createElement('div');
watermarkDiv.id = '__app-waterMark__';
watermarkDiv.setAttribute(
'style',
`pointer-events: none !important;position: absolute !important;z-index: 2147483647 !important;height: 100% !important;width: 100% !important;display: block !important;margin: 0px !important;padding: 0px !important;inset: 0px !important;visibility: visible !important;opacity: 1 !important;clip: auto !important;transform: none !important;filter: none !important;background-size: auto !important;background-position: 0px 0px !important;background-repeat: repeat !important; background-image: ${styles.backgroundImage}`,
);
parentElement.style.position = 'relative';
parentElement.appendChild(watermarkDiv);
};
进阶功能-增加防篡改方法
interface MutationObserverInit {
/** 监听的属性范围,如果设置为undefined | 没有设置表示监听全部的属性 */
attributeFilter?: string[];
/** 是否把 回调函数中的MutationRecord.oldValue 对象是否包含了更改前的数据 */
attributeOldValue?: boolean;
/** 如果要观察目标属性的变化,则设置为true。如果指定了attributeOldValue或attributeFilter,则可以省略 */
attributes?: boolean;
/** 如果要观察目标数据的突变,则设置为true。如果指定了characterDataOldValue,则可以省略 */
characterData?: boolean;
/** 如果characterData设置为true或省略,并且需要记录突变前的目标数据,则设置为true */
characterDataOldValue?: boolean;
/** 如果要观察子节点的插入或删除,则设置为true */
childList?: boolean;
/** 如果不仅要观察到目标的突变,还要观察到目标后代的突变,则设置为true */
subtree?: boolean;
}
type MutationRecordType = 'attributes' | 'characterData' | 'childList' | 'subtree';
interface NodeList {
length: number;
item(index: number): Node | null;
forEach(
callbackfn: (value: Node, key: number, parent: NodeList) => void,
thisArg?: any
): void;
[index: number]: Node;
}
interface MutationRecord {
/**
* 添加的节点
*/
addedNodes: NodeList;
/**
* 更改后的属性名称,否则为null
*/
attributeName: string | null;
/**
* 更改后的属性的命名空间,以及null其他命名空间
*/
attributeNamespace: string | null;
/**
* 添加或删除的节点的下一个同级节点,否则为null
*/
nextSibling: Node | null;
/**
* 返回值取决于类型。对于“attributes”,它是更改前更改的属性的值。对于“characterData”,它是更改前更改节点的数据。对于“childList”,它为null
*/
oldValue: string | null;
/**
* 添加或删除的节点的上一个同级节点,否则为null
*/
previousSibling: Node | null;
/**
* 删除的节点
*/
removedNodes: NodeList;
/**
* 返回受突变影响的节点,具体取决于类型。对于“attributes”,它是属性发生更改的元素。对于“characterData”,它是characterData节点。对于“childList”,它是其子级已更改的节点
*/
target: Node;
/**
* 如果是属性突变,则返回“attributes”。“characterData”,是characterData节点的突变。以及“childList”,是节点树的突变
*/
type: MutationRecordType;
}
type MutationCallback = (
mutations: MutationRecord[],
observer: MutationObserver
) => void;
interface AddMutationObserverParams {
targetNode: Node;
callback: MutationCallback;
config?: MutationObserverInit;
}
const addMutationObserver = (data: AddMutationObserverParams) => {
const { callback, targetNode, config } = data;
const defaultConfig: MutationObserverInit = {
childList: true,
};
// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);
// 以上述配置开始观察目标节点
observer.observe(targetNode, config || defaultConfig);
return observer;
};
const disconnectObserve = (observer: MutationObserver) => {
observer && observer.disconnect();
};
// 创建水印或者页面挂载之后初始化监控
const initMutationObserver = (targetNode: HTMLElement) => {
const currentTargetNode = targetNode || document.body;
this.observer = addMutationObserver({
currentTargetNode,
callback: (mutations) => {
// mutations可以拿到水印元素是否变化(判断逻辑不再赘述),如果水印变化了重新调用创建水印方法即可
},
});
}
// 页面卸载之后要移除监控
this.observer && disconnectObserve(this.observer);