最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2024年06月11日 08:49:53   作者:十串  
這篇文章主要介紹了關(guān)于JS前端實(shí)現(xiàn)水印的代碼操作,文中給出了詳細(xì)的實(shí)現(xiàn)思路和代碼示例供大家參考,對(duì)大家的學(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)
        }
      }
    }
  });
  // 啟動(dòng)監(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的變化會(huì)立即觸發(fā)對(duì)應(yīng)的事件,而 MutationObserver 是異步的,會(huì)在下一個(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變動(dòng)時(shí),是否需要記錄變動(dòng)前的屬性值
  attributeFilter: [‘class',‘src']  // 需要觀察的特定屬性

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

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

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

// 清除變動(dòng)記錄
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格式會(huì)對(duì)透明區(qū)域做顏色填充)。

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

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

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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript滿天星導(dǎo)航欄實(shí)現(xiàn)方法

    JavaScript滿天星導(dǎo)航欄實(shí)現(xiàn)方法

    本篇文章給大家分享了JavaScript滿天星導(dǎo)航欄實(shí)現(xiàn)方法,以前也介紹過很多關(guān)于特效導(dǎo)航的制作方法,對(duì)此有興趣的朋友參考學(xué)習(xí)下。
    2018-03-03
  • input輸入框限制只能輸入數(shù)字的方法實(shí)例(個(gè)人認(rèn)為最好的)

    input輸入框限制只能輸入數(shù)字的方法實(shí)例(個(gè)人認(rèn)為最好的)

    在很多業(yè)務(wù)中需要對(duì)輸入框進(jìn)行字符限制,比如金額輸入框、手機(jī)號(hào)碼輸入框等,下面這篇文章主要給大家介紹了關(guān)于input輸入框限制只能輸入數(shù)字的相關(guān)資料,文中介紹的方法個(gè)人認(rèn)為最好的,需要的朋友可以參考下
    2022-10-10
  • TypeScript中Babel編譯器的具體使用

    TypeScript中Babel編譯器的具體使用

    本文主要介紹了TypeScript中Babel編譯器的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-05-05
  • 小程序?qū)崿F(xiàn)篩子抽獎(jiǎng)

    小程序?qū)崿F(xiàn)篩子抽獎(jiǎng)

    這篇文章主要為大家詳細(xì)介紹了小程序?qū)崿F(xiàn)篩子抽獎(jiǎng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • 如何實(shí)現(xiàn)修改密碼時(shí)密碼框顯示保存到cookie的密碼

    如何實(shí)現(xiàn)修改密碼時(shí)密碼框顯示保存到cookie的密碼

    修改密碼時(shí)密碼框顯示保存到cookie的密碼,只要在input框中加入AUTOCOMPLETE="OFF" 即可,感興趣的朋友可以了解下
    2013-12-12
  • echarts進(jìn)度條加描述實(shí)例代碼舉例

    echarts進(jìn)度條加描述實(shí)例代碼舉例

    ECharts是一款基于JavaScript的數(shù)據(jù)可視化庫,可以用來創(chuàng)建各種各樣的交互式圖表和可視化效果,這篇文章主要介紹了echarts進(jìn)度條加描述實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2026-06-06
  • 小程序開發(fā)基礎(chǔ)之view視圖容器

    小程序開發(fā)基礎(chǔ)之view視圖容器

    這篇文章主要介紹了小程序開發(fā)基礎(chǔ)之view視圖容器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • Bootstrap下拉菜單Dropdowns的實(shí)現(xiàn)代碼

    Bootstrap下拉菜單Dropdowns的實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Bootstrap下拉菜單Dropdowns的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • JavaScript 函數(shù)式編程的原理

    JavaScript 函數(shù)式編程的原理

    要了解JavaScript中的函數(shù)式編程原理,必須理解一下兩個(gè)知識(shí)點(diǎn)
    2009-10-10
  • js 計(jì)數(shù)排序的實(shí)現(xiàn)示例(升級(jí)版)

    js 計(jì)數(shù)排序的實(shí)現(xiàn)示例(升級(jí)版)

    這篇文章主要介紹了js 計(jì)數(shù)排序的實(shí)現(xiàn)示例(升級(jí)版),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01

最新評(píng)論

山阳县| 封丘县| 庆阳市| 青海省| 读书| 西藏| 英吉沙县| 抚顺市| 普陀区| 廊坊市| 前郭尔| 德化县| 宁武县| 新乐市| 龙陵县| 遂平县| 伊春市| 共和县| 湖北省| 西藏| 稻城县| 新干县| 呼伦贝尔市| 肇庆市| 开远市| 松阳县| 白朗县| 政和县| 安平县| 利川市| 平和县| 新津县| 兴和县| 罗城| 刚察县| 星子县| 外汇| 汶上县| 美姑县| 长春市| 宣恩县|