js创建水印

文章介绍了如何使用JavaScript创建可定制的水印功能,并结合MutationObserver来检测DOM元素变化,防止水印被篡改。作者展示了获取水印图片、创建水印元素、以及使用MutationObserver进行实时监控的方法。
摘要由CSDN通过智能技术生成

 编写创建水印函数

// 获取水印图片
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);
    

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值