首页 > 其他分享 >自适应且不可删除的水印蒙层

自适应且不可删除的水印蒙层

时间:2022-12-08 14:36:21浏览次数:33  
标签:el style 删除 蒙层 ctx 水印 important let

canvas自适应文字长度,旋转角度生成水印背景图

  • 设置canvas字体大小后,通过ctx.measureText(text).width获取两行文字的宽度text1,text2,取最大宽度为文本框宽度textWidth
  • 设置两行文字间距,可得文本框高度:textHeight=2*fontsize+ space_line
  • 计算最小一个能够完全包裹旋转后文本的盒子宽高
    已知旋转角度为rotate=>得到弧度rad = (rotate*Math.pi) /180
    单个水印图平铺成为蒙层的背景图,space_x,space_y用于调整水印之间的间距
  function  drawWatermark(el, config = {}) {
      if (!el) return;
      // 默认配置
      let {
        text1 = '今天也要保持愉悦鸭~', //文本1
        text2 = '2022-12-07', // 文本2
        space_x = 0, // x轴间距 
        space_y = 0, // y轴间距
        space_line = 20, //两列文字的间距
        font = 'Microsoft JhengHei bold',
        fontSize = 40, // 字体
        color = 'rgba(22,22,22,1)', // 字色
        rotate = 30 // 倾斜度
      } = config;
      const canvas =  document.createElement('canvas');
      el.appendChild(canvas);
      const ctx = canvas .getContext('2d');
      ctx.font = fontSize + 'px ' + font; //设置好fontsize才能正确计算出文本宽度
      let tw1= ctx.measureText(text1).width;
      let tw2= ctx.measureText(text2).width;
      let textWidth = Math.max(tw1, tw2); //文本最长宽度为文本框宽度
      let textHeight = fontSize * 2 + space_line; //文本框高度为两个文本+行间距
      let rad  = (rotate * Math.PI) / 180; //角度转弧度
      let sin = Math.sin(rad ); 
      let cos = Math.cos(rad );
      let width = textWidth * cos + textHeight * sin + space_x ; //为包裹住文本框的最小盒子宽度
      let height = textWidth * sin + textHeight * cos + space_y; //为包裹住文本框的最小盒子高度
      canvas.width = width;
      canvas.height = height;
      canvas.style.cssText = `width:${width}px;height:${height}px;display:none;`;
      ctx.translate(space_x , textWidth * sin + space_y );  // 移动旋转中心
      ctx.rotate((-1 * (rotate * Math.PI)) / 180); //旋转文本框
      ctx.fillStyle = color;
      ctx.textAlign = 'left';
      ctx.textBaseline = 'middle';
      ctx.font = fontSize + 'px ' + font;
      ctx.fillText(text1, (textWidth - tw1) / 2, 0.5 * fontSize);  //文本在文本框中居中显示
      ctx.fillText(text2, (textWidth - tw2) / 2, 1.5 * fontSize + space_line); //文本在文本框中居中显示
      return canvas.toDataURL('image/png');
    },

生成蒙层

在目标元素下添加一个相对定位的子元素,将水印图片平铺作为背景图。

禁止蒙层的删除和修改

  • 删除或移动element
  • 修改style

transform: translate(100%,100%);
display: none;
visibility: hidden;
取消背景图

 function createMask(el) {
      //创建蒙层
      let $mask = document.createElement('div');
      //判断蒙层父元素是否有定位
      let position = window.getComputedStyle(el, null).position;
      if (position === 'static') {
        el.style.position = 'relative';
      }
      //设置蒙层样式
      let style = `visibility: visible !important;
        transform: translate(0,0)  !important;
        display: block !important;
        visibility: visible !important;
        width: 100% !important; 
        height: 100% !important;
        pointer-events: none !important; 
        background-color: rgba(0, 0, 0, 0)!important;
        background-repeat: repeat !important;
        position: absolute !important;
        top: 0px !important;
        left: 0px !important;
        z-index: 999 !important; 
        background-image: url(${drawWatermark(el)}) !important`;
      $mask.setAttribute('style', style);
      //添加蒙层
      el.append($mask);
      // 创建MutationObserver
      el.observer = new MutationObserver((mutationRecord) => {
        //处理DOM
        mutationRecord.forEach((mutation) => {
          // 蒙层删除或者被移动到别处
          if (mutation.target === el && mutation.removedNodes[0] == $mask) {
            el.append($mask);
          } else if (mutation.target == $mask && mutation.attributeName === 'style') {
            // 蒙层被更改样式 在监听到蒙层样式更改后,赋值的新的样式会导致再次触发监听回调,所以需要在监听事件中判断何时需要赋值
            const changestyle = $mask?.getAttribute('style');
            if (changestyle !== style) {
              $mask.setAttribute('style', style);
            }
          }
        });
      });
      // 启动监控
      el.observer.observe(el, {
        childList: true,
        attributes: true,
        subtree: true
      });
      return $mask;
    },

行内样式加important是为了防止通过添加class或其他css覆盖样式(暂时没有找到怎么如何通过修改css的方式更改样式的监听方式)
踩得一个坑
设置元素的行内样式有很多种

let style = 'width:100%;height:100%' 适用单个样式更改
element.style.width =100% ;element.style['height'] =100%
element.style.cssText = style
element.setAttribute('style',style )

方式二设置样式后,行内样式格式和赋值时的style的格式不一样,获取到行内style后直接进行===判断,回造成死循环

解决方法:

  • 第一次监听到蒙层更改时,立刻移除蒙层,重新生成新蒙层
  • 写个函数判断不同格式的两个样式属性上是否相等

标签:el,style,删除,蒙层,ctx,水印,important,let
From: https://www.cnblogs.com/wwwxxxyyy/p/16963848.html

相关文章

  • linux 中删除匹配内容的下一行
     001、[root@PC1test]#lsa.txt[root@PC1test]#cata.txt##测试数据12345678[root@PC1test]#sed'/4/{n;d}'a.txt##删除匹配4的下......
  • VS快速删除空白行
    使用快捷键Ctrl+H,打开替换框。使用快捷键Alt+R或者点击下图红框图标,选择使用“正则表达式”。输入正则表达式:^\s*(?=\r?$)\n,如下图:......
  • VS/C#删除程序中的空白行
    按下键盘"Ctrl"+"H",在被替换行输入^\s*$  勾选替换下方的"使用正则表达式"或者按下"Ctrl"+"E"点击替换行的"全部替换"或者按下快捷键"Ctrl"+"A"完美替换......
  • Oracle误删除数据的恢复
    Oracle误删除数据的恢复在平时操作数据库时,难免会误删数据,或者表格,这时候不用慌张,按照如下步骤进行恢复:删除的操作有三种:DELETE和TRUNCATE只删除数据,DROP则删除整个表(......
  • logback过期日志文件自动删除
    前言logback应该是目前最主流的日志框架了,在实际使用中经常遇到打印的日志文件不会自动删除,导致日志文件占有大量磁盘空间的问题。本文主要介绍logback日志文件自动删除的实......
  • 针对数据库逻辑删除操作简单实现方案
    数据库逻辑删除定义逻辑删除是指在删除数据库的某条记录时,并不是真正的将该条记录删除,而是通过某个字段来标识其状态为“删除”,在接下来的查询等操作时,根据此字段来过滤......
  • 【mysql】误删除了自带的mysql数据库后该怎么恢复?
    前言如果mysql数据库系统自带的mysql数据库被误删了,应该如何恢复?其实操作方法比较简答,今天用实验的方式分享一下1、实验环境信息实验环境信息:mysql版本5.7......
  • PS---套索工具del键删除不了【解决方案】
    最近在用PS进行一些抠图操作,遇到一个奇怪的问题,就是使用套索工具来选择后,按删除键,删除不了点,或者是在删除点后,就无法再次选中的问题。万万没想到这个是微软输入法的问题:wi......
  • MyBatisplus3.12.CRUD扩展:自动填充。乐观锁。分页查询。逻辑删除SpringBoot环境
    简介:大家好,我是枫哥,......
  • js移除数组,删除数组
    一、修改arr的length方法根据修改后的length去除后面的元素。letarr=[1,2,3,4,5,6,7,8,9];arr.length=3;console.log('length',arr.length);//3console.log('a......