亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于JS前端實(shí)現(xiàn)水印的代碼操作

 更新時(shí)間:2024年06月11日 08:49:53   作者:十串  
這篇文章主要介紹了關(guān)于JS前端實(shí)現(xiàn)水印的代碼操作,文中給出了詳細(xì)的實(shí)現(xiàn)思路和代碼示例供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

網(wǎng)頁水印

實(shí)現(xiàn)思路

  • 通過canvas生成一張水印圖片
  • 通過css將圖片設(shè)置為目標(biāo)節(jié)點(diǎn)的背景圖
  • 通過MutationObserver監(jiān)聽目標(biāo)節(jié)點(diǎn)的類名變化,防止水印被刪除

代碼操作

  • 通過canvas生成一張水印圖片
function createImgBase(options) {
  const { content, width, height } = options;
  const canvasDom = document.createElement("canvas");
  let ctx = canvasDom.getContext("2d");
  canvasDom.width = width;
  canvasDom.height = height;
  if (ctx) {
    // 設(shè)置畫筆的方向
    ctx.rotate((-14 * Math.PI) / 180);
    // 設(shè)置水印樣式
    ctx.fillStyle = "rgba(100,100,100,0.4)";
    ctx.font = "italic 20px Arial";
    // 渲染水印
    content.forEach((text, index) => {
      ctx.fillText(text, 10, 30 * (index + 1)); // 縱向拉開30的間距
    });
  }
  // document.body.appendChild(canvasDom);
  // 將canvas轉(zhuǎn)為圖片
  return canvasDom.toDataURL("image/png");
}

// createImgBase({
//   content: ["介四嘛呀", "介四sui印", "內(nèi)部機(jī)密材料", "嚴(yán)禁外泄!"],
//   width: 200,
//   height: 200,
// });
  • 將水印設(shè)置為目標(biāo)節(jié)點(diǎn)的背景圖片
function getWaterMark({
  content,
  className,
  canvasHeight = 140,
  canvasWidth = 150,
}) {
  // 生成圖片
  const data_url = createImgBase({
    content,
    width: canvasWidth,
    height: canvasHeight,
  });
  // 通過設(shè)置偽元素樣式,添加水印圖片為背景圖
  const defaultStyle = `
  .${className} {
    position: relative;
  }
  .${className}::after {
    content: "";
    background-image: url(${data_url});
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    pointer-events: none;
  }`;

  const styleDom = document.createElement("style");
  styleDom.innerHTML = defaultStyle;
  document.head.appendChild(styleDom);
}
// getWaterMark({
//   content: ["介四嘛呀", "介四sui印", "內(nèi)部機(jī)密材料", "嚴(yán)禁外泄!"],
//   className: "content",
// });
  • 添加mutationObserver監(jiān)聽節(jié)點(diǎn)的變化
function listenerDOMChange(className) {
  // 獲取要監(jiān)聽的節(jié)點(diǎn)
  const targetNode = document.querySelector(`.${className}`);
  // 創(chuàng)建監(jiān)聽器
  const observer = new MutationObserver(mutationList => {
    // 遍歷變化記錄
    for (let mutationRecord of mutationList) {
      // 如果目標(biāo)節(jié)點(diǎn)的class屬性發(fā)生變化,判斷是不是類名被刪了,是的話把類名加回去
      if (mutationRecord.attributeName === "class") {
        if(!Array.from(targetNode.classList).includes(className)) {
          targetNode.classList.add(className)
        }
      }
    }
  });
  // 啟動監(jiān)聽
  observer.observe(targetNode, {
    attributes: true,
  });
}

function getWaterMark({
      content,
      className,
      canvasHeight = 140,
      canvasWidth = 150,
}) {
  // 監(jiān)聽
  listenerDOMChange(className);
  const data_url = createImgBase({
    content,
    width: canvasWidth,
    height: canvasHeight,
  });
  // ...
  const styleDom = document.createElement("style");
  styleDom.innerHTML = defaultStyle;
  document.head.appendChild(styleDom);
}

關(guān)于MutationObserver

MutationObserver 用來監(jiān)聽DOM的變化,DOM的增刪、DOM屬性的變化,子結(jié)點(diǎn)和文本內(nèi)容的變化,都可以被監(jiān)聽。

MutationObserver 的監(jiān)聽和事件不同,事件是同步的,DOM的變化會立即觸發(fā)對應(yīng)的事件,而 MutationObserver 是異步的,會在下一個(gè)微任務(wù)執(zhí)行時(shí)觸發(fā)監(jiān)聽回調(diào)。

  • 創(chuàng)建MutationObserver
const observer = new MutationObserver((mutationsList, observer) => {
    // mutationsList mutationRecord數(shù)組 記錄了DOM的變化
    // observer MutationObserver的實(shí)例

    // 監(jiān)聽回調(diào)
    console.log(mutationsList, observer);
})

mutationObserver.observe(document.documentElement, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true
});
  • 開啟監(jiān)聽
// node 監(jiān)聽的節(jié)點(diǎn)
// config 監(jiān)聽配置(要監(jiān)聽哪些內(nèi)容)
// observer.observe(node, config);
mutationObserver.observe(document.documentElement, {
  attributes: true,  // 屬性變化
  attributeOldValue: true,  // 觀察attributes變動時(shí),是否需要記錄變動前的屬性值
  attributeFilter: [‘class',‘src']  // 需要觀察的特定屬性

  characterData: true,  // 節(jié)點(diǎn)內(nèi)容、文本的變化
  characterDataOldValue: true,  // 觀察characterData變動時(shí),是否需要記錄變動前的屬性值

  childList: true,  // 子結(jié)點(diǎn)變化
  subtree: true,    // 所有后代節(jié)點(diǎn)
});

// 停止監(jiān)聽
mutationObserver.disconnect()

// 清除變動記錄
mutationObserver.takeRecords()

圖片水印

實(shí)現(xiàn)思路

方案一:通過oss添加水印 方案二:通過canvas生成帶有水印的圖片

oss實(shí)現(xiàn)

oss方式不做過多描述了 簡單來說就是通過在獲取圖片時(shí),在圖片鏈接上增加參數(shù),讓oss生成一張帶水印的圖片。 注意點(diǎn):

  • png圖片的透明區(qū)域無法被添加水印。 解決方式: 可通過添加參數(shù)的方式,讓oss將圖片轉(zhuǎn)為jpg格式(jpg格式會對透明區(qū)域做顏色填充)。

  • 字體大小寫為定值,原圖大小會影響到水印字體的顯示大小。 解決方式:通過創(chuàng)建img標(biāo)簽,onLoad獲取圖片后,根據(jù)圖片寬高計(jì)算合適的字體大小,然后再一次獲取帶水印的圖片。

  • 用戶通過刪除參數(shù)的方式可以刪除水印 解決方式:設(shè)置oss的安全級別,不帶水印不可訪問。

canvas實(shí)現(xiàn)

  • 將img轉(zhuǎn)為canvas
async function imgToCanvas(cav, imgSrc) {
  const img = new Image();
  img.src = imgSrc;
  // 防止因跨域?qū)е碌膱D片加載失敗(該方法有局限性)
  img.setAttribute("crossOrigin", "anonymous");
  // 等待圖片加載
  await new Promise(resolve => (img.onload = resolve));
  cav.width = img.width;
  cav.height = img.height;
  const ctx = cav.getContext("2d");
  if (ctx) {
    ctx.drawImage(img, 0, 0);
  }
  return cav;
}
  • 添加水印
function addWaterMask(cav, content) {
  const ctx = cav.getContext("2d");
  ctx.fillStyle = "rgba(100,100,100,0.2)";
  ctx.font = `24px serif`;
  ctx.translate(0, 0);
  ctx.rotate((5 * Math.PI) / 180);
  // 生成水印
  let x = 0, y = 0;
  while (x < cav.width) {
    y = 0;
    while (y < cav.height) {
      ctx.fillText(content, x, y);
      y += 100;
    }
    x += 150;
  }
}
  • 使用
(async function () {
  const canvas = document.createElement("canvas");
  await imgToCanvas(
    canvas,
    "https://pp.myapp.com/ma_pic2/0/shot_54360764_1_1716462139/0"
  );
  addWaterMask(canvas, "介四sui印");
  // document.body.appendChild(canvas);
  return canvas.toDataUrl("image/png")
})();

到此這篇關(guān)于關(guān)于JS前端實(shí)現(xiàn)水印的代碼操作的文章就介紹到這了,更多相關(guān)JS實(shí)現(xiàn)水印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何用RxJS實(shí)現(xiàn)Redux Form

    如何用RxJS實(shí)現(xiàn)Redux Form

    這篇文章主要介紹了如何用RxJS實(shí)現(xiàn)Redux Form,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • JavaScript this綁定過程深入詳解

    JavaScript this綁定過程深入詳解

    這篇文章主要介紹了JavaScript this綁定過程,結(jié)合實(shí)例形式深入分析了JavaScript中this關(guān)鍵字的功能、原理、綁定方式及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2018-12-12
  • js獲取URL的參數(shù)的方法(getQueryString)示例

    js獲取URL的參數(shù)的方法(getQueryString)示例

    getQueryString方法默認(rèn)返回的是 string如果是int類型,則JS使用的時(shí)候,要進(jìn)行轉(zhuǎn)換一下,下面有個(gè)不錯(cuò)的示例,大家可以參考下
    2013-09-09
  • js實(shí)現(xiàn)簡單的購物車有圖有代碼

    js實(shí)現(xiàn)簡單的購物車有圖有代碼

    這篇文章主要介紹了用js實(shí)現(xiàn)的簡單購物車,配有截圖,適合初學(xué)者
    2014-05-05
  • JavaScript中的for...of和for...in循環(huán)容易遇到的問題及解決方法總結(jié)

    JavaScript中的for...of和for...in循環(huán)容易遇到的問題及解決方法總結(jié)

    在 JavaScript 編程中,for...of 和 for...in 是常用的循環(huán)語法,但它們在使用時(shí)可能會引發(fā)一些意想不到的問題,本文將分享我在使用這兩種循環(huán)時(shí)所遇到的坑和經(jīng)驗(yàn),需要的朋友可以參考下
    2023-08-08
  • pdfmake生成pdf的使用方法

    pdfmake生成pdf的使用方法

    本文介紹了如何使用pdfmake第三方庫在項(xiàng)目中根據(jù)模板生成PDF文件,文中還提到了常用的配置,如頁眉和頁腳效果,對pdfmake pdf使用方法感興趣的朋友一起看看吧
    2024-09-09
  • Valerio 發(fā)布了 Mootools

    Valerio 發(fā)布了 Mootools

    Valerio 發(fā)布了 Mootools...
    2006-09-09
  • 第二章之Bootstrap 頁面排版樣式

    第二章之Bootstrap 頁面排版樣式

    Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的,它簡潔靈活,使得 Web 開發(fā)更加快捷。本文給大家介紹Bootstrap 頁面排版樣式的相關(guān)知識,希望對大家有所幫助!
    2016-04-04
  • JavaScript之clipboard用法詳解

    JavaScript之clipboard用法詳解

    這篇文章主要介紹了JavaScript之clipboard用法詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • js png圖片(有含有透明)在IE6中為什么不透明了

    js png圖片(有含有透明)在IE6中為什么不透明了

    png-8模式的圖片,如果沒有漸變的話是透明的,如果有漸變就不透明了。需要js的支持。
    2010-02-02

最新評論