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

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

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

網(wǎng)頁水印

實現(xiàn)思路

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

代碼操作

  • 通過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é)點的背景圖片
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é)點的變化
function listenerDOMChange(className) {
  // 獲取要監(jiān)聽的節(jié)點
  const targetNode = document.querySelector(`.${className}`);
  // 創(chuàng)建監(jiān)聽器
  const observer = new MutationObserver(mutationList => {
    // 遍歷變化記錄
    for (let mutationRecord of mutationList) {
      // 如果目標(biāo)節(jié)點的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é)點和文本內(nèi)容的變化,都可以被監(jiān)聽。

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

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

    // 監(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é)點
// config 監(jiān)聽配置(要監(jiān)聽哪些內(nèi)容)
// observer.observe(node, config);
mutationObserver.observe(document.documentElement, {
  attributes: true,  // 屬性變化
  attributeOldValue: true,  // 觀察attributes變動時,是否需要記錄變動前的屬性值
  attributeFilter: [‘class',‘src']  // 需要觀察的特定屬性

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

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

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

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

圖片水印

實現(xiàn)思路

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

oss實現(xiàn)

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

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

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

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

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

相關(guān)文章

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

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

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

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

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

    TypeScript中Babel編譯器的具體使用

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評論

湖南省| 泗洪县| 桐庐县| 皋兰县| 图们市| 广水市| 津南区| 峨眉山市| 东乡县| 湟中县| 安陆市| 洮南市| 永仁县| 四子王旗| 厦门市| 会宁县| 奉新县| 北安市| 阳山县| 响水县| 景泰县| 娄烦县| 永济市| 鞍山市| 小金县| 甘孜县| 四川省| 宾川县| 额济纳旗| 兴仁县| 大城县| 舒兰市| 望江县| 报价| 屏东市| 沙雅县| 林芝县| 鄱阳县| 老河口市| 河东区| 岐山县|