前端使用水印的代码实现

2 篇文章 0 订阅
1 篇文章 0 订阅

第一点

很好实现。我们create一个dom元素,插入到body中就可以了。

 const divObj = document.createElement('div');
    const styleStr = `
                  position:fixed;
                  top:0;
                  left:0;
                  bottom:0;
                  right:0;
                  z-index:999999;
                  background-repeat:repeat;
                  `;
    divObj.setAttribute('style', styleStr);
    document.body.appendChild(divObj);

第二点

水印的内容我们从cookie中获取一下。

 const user = /user_name=([^;]+)/.exec(document.cookie);
 const name = Array.isArray(user) && user.length === 2 && user[1] ? user[1] : '配置的水印';

第三点

这两个综合考虑的话,将name作为一个背景图 然后repeat就可以了。我们要将文字转为图片,那么canvas是一个不错的选择。同时我们要考虑到这个图片不易过大(为了符合第三点),所以我们就按照100*100的尺寸吧。

    const canvasObj = document.createElement('canvas');
    const canvas2d = canvasObj.getContext('2d');
    canvasObj.width = 100;
    canvasObj.height = 100;
    canvas2d.font = fontSize + 'px Arial';
    canvas2d.fillStyle = 'rgba(128,128,128,.6)'; // 这里文字的颜色淡一点,不要影响整体的美观
    canvas2d.translate(canvasObj.width / 4, canvasObj.height / 2);
    canvas2d.rotate((-30 / 180) * Math.PI);
    canvas2d.fillText(name, 0, canvasObj.height / 2);
    // 将canvas 转为 dataURL
    const base64Url = canvasObj.toDataURL('image/png');

第四点

要有防窜改的功能,具体要体现在我们创建的水印不能轻易的让别人给删了,其次,水印内容也不能轻易的被改了,无论是水印内容或者是水印的颜色样式等。

水印内容这一块因为我们使用的是cookie中的登录信息,如果有人更改了cookie中的值,会导致登录信息失效,在sso这一侧就会被强制跳转到登录页面,所以这个可以交由登录系统来做。

我们的dom不能轻易的被删除和更改样式,那么我们就需要用到 MutationObserver 这个api了,他的作用就是监听DOM的变化,并触发一个回调,我们只需在回调中重新执行水印的方法就可以避免这个问题。

   if (MutationObserver) {
      let waterMarkOb = new MutationObserver(function () {
        const _globalWatermark = document.querySelector(`domId`);
        // 当样式或者水印元素dom节点有改动时会重新绘制
        if (
          (_globalWatermark && _globalWatermark.getAttribute('style') !== styleStr) ||
          !_globalWatermark
        ) {
          waterMarkOb.disconnect();
          waterMarkOb = null;
          setWaterMark();
        }
      });
      // 指定观察对象
      waterMarkOb.observe(document.body, {
        attributes: true,
        subtree: true,
        childList: true,
      });
    }

最后一点

注意事项中有一点,就是我们的水印功能尽可能的不要影响到业务的使用。 所以这里我们要考虑两点:

1. 我们的水印dom在全屏幕的最上层,虽然层级在99999,但是也不要要影响到下面的元素操作。所以我们需要增加pointer-events:none 的属性,不影响鼠标的操作。

2. 我们要在前端代码不变动的情况下上线水印的功能,那我们就要从服务器上入手了,比如在nginx中,我们可以使用 sub_filter 模块来替换返回的文本。例如

 subs_filter "(<\/body>)" "$1<script src=\"https://cdn.xxx.com/watermark.js\"></script>" irg;

整体代码

!(function () {
  // 一个配置
  const options = {
    id: 'globalWaterMark',
    fontSize: 10,
    color: 'rgba(128,128,128,.6)',
    rotate: '-30',
    userName: "其他的身份"
  };

  /**
   * 创建水印图片url
   */
  function createWaterMark() {
    const { fontSize, color, id } = options;
    const user = /user_name=([^;]+)/.exec(document.cookie);
    const name = Array.isArray(user) && user.length === 2 && user[1] ? user[1] : options.userName;
    const canvasObj = document.createElement('canvas');
    const canvas2d = canvasObj.getContext('2d');
    canvasObj.width = 200;
    canvasObj.height = 100;
    canvas2d.font = fontSize + 'px Arial';
    canvas2d.fillStyle = color;
    canvas2d.translate(canvasObj.width / 4, canvasObj.height / 2);
    canvas2d.rotate((-30 / 180) * Math.PI);
    canvas2d.fillText(name, 0, canvasObj.height / 2);
    // 将canvas 转为 dataURL
    const base64Url = canvasObj.toDataURL('image/png');
    return base64Url;
  }

  function setWaterMark() {
    const { fontSize, color, id } = options;
    const url = createWaterMark();
    const target = document.getElementById(id);
    if(target){
      document.body.removeChild(target)
    }
    const divObj = document.createElement('div');
    divObj.id = options.id;
    const styleStr = `
                  position:fixed;
                  top:0;
                  left:0;
                  bottom:0;
                  right:0;
                  z-index:999999;
                  background-repeat:repeat;
                  pointer-events:none;
                  background-image:url('${url}')`;
    divObj.setAttribute('style', styleStr);
    document.body.appendChild(divObj);
    // 监听DOM变动
    const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    if (MutationObserver) {
      let waterMarkOb = new MutationObserver(function () {
        const _globalWatermark = document.querySelector(`#${id}`);
        // 当样式或者水印元素dom节点有改动时会重新绘制
        if (
          (_globalWatermark && _globalWatermark.getAttribute('style') !== styleStr) ||
          !_globalWatermark
        ) {
          waterMarkOb.disconnect();
          waterMarkOb = null;
          setWaterMark();
        }
      });
      // 指定观察对象
      waterMarkOb.observe(document.body, {
        attributes: true,
        subtree: true,
        childList: true,
      });
    }
  }

  document.addEventListener('DOMContentLoaded', function () {
    setWaterMark();
  });
})();

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值