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,
    });
  },
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

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