首页前端工具函数Canvas添加水印

Canvas添加水印

分类前端工具函数时间2024-03-15 12:27:51发布RustStream浏览61
摘要:声明一个hooks /hooks/useWatermarkBg.js import { computed } from 'vue'; export default function useWatermarkBg (props { return computed(( => { // 创建一个 canvas const canvas = document.createElement('canvas' ; const devicePixelRatio = window.devicePixelRatio || 1; // 设置字体大小 const fontSize = props.fontSize * devicePixelRatio; const font = fontSize + 'px serif'; const ctx = canvas.getContext('2d' ; // 获取文字宽度 ctx.font = font; const { width } = ctx.measureText(props.text ; const canvasSize = Math.max(100, width + props.gap * devicePixelRatio; canvas.width = canvasSize; canvas.height = canvasSize; ctx.translate(canvas.width / 2, canvas.height / 2 ; // 旋转角度让文字变倾斜 ctx.rotate((Math.PI / 180 * - props.rotate ; ctx.fillStyle = props.fillStyle; ctx.font = font; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // 将文字画出来 ctx.fillText(props.text, 0, 0 ; return { base64: canvas.toDataURL( , size: canvasSize, styleSize: canvasSize / devicePixelRatio, }; } ; } 封装一个组件 components/WatermarkBg/index.vue <template<!--autointro-->...

声明一个hooks

/hooks/useWatermarkBg.js
import { computed } from 'vue';
export default function useWatermarkBg (props) {
  return computed(() => {
      // 创建一个 canvas
      const canvas = document.createElement('canvas');
      const devicePixelRatio = window.devicePixelRatio || 1;
      // 设置字体大小
      const fontSize = props.fontSize * devicePixelRatio;
      const font = fontSize + 'px serif';
      const ctx = canvas.getContext('2d');
      // 获取文字宽度
      ctx.font = font;
      const { width } = ctx.measureText(props.text);
      const canvasSize = Math.max(100, width) + props.gap * devicePixelRatio;
      canvas.width = canvasSize;
      canvas.height = canvasSize;
      ctx.translate(canvas.width / 2, canvas.height / 2);
      // 旋转角度让文字变倾斜
      ctx.rotate((Math.PI / 180) * - props.rotate);
      ctx.fillStyle = props.fillStyle;
      ctx.font = font;
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      // 将文字画出来
      ctx.fillText(props.text, 0, 0);
      return {
          base64: canvas.toDataURL(),
          size: canvasSize,
          styleSize: canvasSize / devicePixelRatio,
      };
  });
}

封装一个组件

components/WatermarkBg/index.vue
<template>
    <div class="watermark-container" ref="parentRef">
      <slot></slot>
    </div>
  </template>
   
  <script setup>
  import { onMounted, onUnmounted, ref, watchEffect } from 'vue';
  import useWatermarkBg from '@/hooks/useWatermarkBg.js';
   
  const props = defineProps({
    text: {
      type: String,
      required: true,
      default: '禁止截图外传',
    },
    fontSize: {
      type: Number,
      default: 20,
    },
    gap: {
      type: Number,
      default: 50,
    },
    fillStyle: {
        type: String,
        default: 'rgba(0, 0, 0,0.3)'
    },
    rotate: {
        type: Number,
        default: -22
    }
  });
   
  const bg = useWatermarkBg(props);
  const parentRef = ref(null);
  const flag = ref(0); // 声明一个依赖
  let div;
   
  watchEffect(() => {
    flag.value; // 将依赖放在 watchEffect 里
    if (!parentRef.value) {
      return;
    }
    if (div) {
      div.remove();
    }
    const { base64, styleSize } = bg.value;
   
    div = document.createElement('div');
    div.style.backgroundImage = `url(${base64})`;
    div.style.backgroundSize = `${styleSize}px ${styleSize}px`;
    div.style.backgroundRepeat = 'repeat';
    div.style.zIndex = 9999;
    div.style.position = 'absolute';
    div.style.inset = 0;
    // 元素不会接收鼠标事件,鼠标事件会透过元素传递到下层的元素上
    div.style.pointerEvents = 'none';
    parentRef.value.appendChild(div);
  });
   
  // 防篡改处理
  let ob;
  onMounted(() => {
    ob = new MutationObserver((records) => {
      for (const record of records) {
        for (const dom of record.removedNodes) {
          if (dom === div) {
            flag.value++; // 删除节点的时候更新依赖
            return;
          }
        }
        if (record.target === div) {
          flag.value++; // 修改属性的时候更新依赖
          return;
        }
      }
    });
    ob.observe(parentRef.value, {
      childList: true,
      attributes: true,
      subtree: true,
    });
  });
   
  onUnmounted(() => {
    ob && ob.disconnect();
    div = null;
  });
  </script>

使用

APP.vue

<template>

  <WatermarkBg :text="text">
    <router-view />
  </WatermarkBg>
  
</template>

本文链接:https://blog.smallhao.fun/?id=23 转载需授权!

分享到:

Chen’Blog版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

JavaScript
webpack Vite+Vue3 + Echarts 封装

游客 回复需填写必要信息
召唤伊斯特瓦尔