svg 水印

改造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,
    });
  },
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 有个web项目要有水印需求,后端可以提供文本或者图片。参考网络上的前端水印方案,目前选择的是获取文本,通过文本生成...
    celineWong7阅读 1,295评论 0 0
  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,749评论 1 180
  • 导语:前段时间做某系统审核后台,出现了审核人员截图把内容外泄露的情况,虽然截图内容不是特别敏感,但是安全问题还是不...
    李亚_45be阅读 1,206评论 0 0
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 13,089评论 2 59
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,276评论 4 61