svg 水印

改造svg全屏水印

支持防刪
支持動(dòng)態(tài)配置

代碼備忘
watermarkSvg.js

/*eslint-disable*/
export function watermark(settings = {}, listening) {
  // 默認(rèn)設(shè)置
  var defaultSettings = {
    watermark_txt: 'text',
    watermark_x: 20, // 水印起始位置x軸坐標(biāo)
    watermark_y: 20, // 水印起始位置Y軸坐標(biāo)
    watermark_rows: 20, // 水印行數(shù)
    watermark_cols: 20, // 水印列數(shù)
    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, // 水印長(zhǎng)度
    watermark_angle: -25, // 水印傾斜度數(shù),
    clear:false, // 清除水印
    ...settings
  };

  var svgXMLLink = 'http://www.w3.org/2000/svg'
  var oTempSvg = document.createElementNS(svgXMLLink, "svg"); // 創(chuàng)建帶有標(biāo)準(zhǔn)svg命名空間的節(jié)點(diǎn)
  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);
  // 如果將水印列數(shù)設(shè)置為0,或水印列數(shù)設(shè)置過大,超過頁面最大寬度,則重新計(jì)算水印列數(shù)和水印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)
  );
  // 如果將水印行數(shù)設(shè)置為0,或水印行數(shù)設(shè)置過大,超過頁面最大長(zhǎng)度,則重新計(jì)算水印行數(shù)和水印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;
    //偶數(shù)行偏移半個(gè)容器寬度
    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;

      // 設(shè)置水印div傾斜顯示
      mask_div.setAttribute("transform", `translate(${x},${y}) rotate(${defaultSettings.watermark_angle})`);
      mask_div.style.visibility = '';

      // 讓水印不遮擋頁面的點(diǎn)擊事件
      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 = []; //已經(jīng)啟動(dòng)的監(jiān)聽列表
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")) {
    // 監(jiān)聽水印自身屬性變化 - 防修改 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")) {
    //監(jiān)聽body - 防止水印自身被刪除
    const $body = document.body;
    let bodyOb = observe(
      $body,
      {
        childList: true,
      },
      function (records, _self) {
        const $watermark = document.querySelector("#waterMarkContainer");
        if (!$watermark) {
          // 被刪后重置所有監(jiān)聽
          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"); // 創(chuàng)建帶有標(biāo)準(zhǔn)svg命名空間的節(jié)點(diǎn)
  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,
    });
  },
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 有個(gè)web項(xiàng)目要有水印需求,后端可以提供文本或者圖片。參考網(wǎng)絡(luò)上的前端水印方案,目前選擇的是獲取文本,通過文本生成...
    celineWong7閱讀 1,390評(píng)論 0 0
  • 用到的組件 1、通過CocoaPods安裝 2、第三方類庫安裝 3、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 15,195評(píng)論 1 180
  • 導(dǎo)語:前段時(shí)間做某系統(tǒng)審核后臺(tái),出現(xiàn)了審核人員截圖把內(nèi)容外泄露的情況,雖然截圖內(nèi)容不是特別敏感,但是安全問題還是不...
    李亞_45be閱讀 1,257評(píng)論 0 0
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 14,030評(píng)論 2 59
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,414評(píng)論 4 61

友情鏈接更多精彩內(nèi)容