背景水印在正常屏幕下显示,全屏情况下不显示,求解?

const watermark: { set: (str: string) => void } = {
    set: function (str: string): void {
    throw new Error("Function not implemented.");
    }
};

let setWatermark = (str: string): string => {
  const id = '1.23452384164.123412415';

  const existingDiv = document.getElementById(id);
  if (existingDiv !== null) {
    document.body.removeChild(existingDiv);
  }

  const can = document.createElement('canvas');
  can.width = 130;
  can.height = 100;

  const cans = can.getContext('2d');
  if (cans !== null) {
    cans.rotate(-20 * Math.PI / 180);
    cans.font = '14px Vedana';
    cans.fillStyle = 'rgba(0, 0, 0, 0.50)';
    cans.textAlign = 'left';
    cans.textBaseline = 'middle';
    cans.fillText(str, can.width / 20, can.height);
  }

  const div = document.createElement('div');
  div.id = id;
  div.style.pointerEvents = 'none';
  div.style.top = '3px';
  div.style.left = '0px';
  div.style.position = 'fixed';
  div.style.zIndex = '100000';
  div.style.opacity = '.4';
  div.style.width = '100vw';
  div.style.height ='100vw';
  div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
  document.body.appendChild(div);


  return id;
};

// 该方法只允许调用一次
watermark.set = (str: string): void => {
  let id = setWatermark(str);
  setInterval(() => {
    const existingDiv = document.getElementById(id);
    if (existingDiv === null) {
      id = setWatermark(str);
    }
  }, 2000);

  window.onresize = () => {
    setWatermark(str);
  };
};

export default watermark;
阅读 1.3k
8 个回答

我之前公司写过那种用 DOM 上创建 N 个 SPAN 然后用 CSS 斜过来的方案。不过这种有点low,用 Canvas 更优雅一些。可以参考上面的方案,

可以使用canvas来实现水印,然后使用mutationObserver来检测元素是否被删改。代码如下:

// 函数buildWatermark()用于创建一个画布,并绘制文本,返回该画布
function buildWatermark() {
  // 创建一个画布
  const canvas = document.createElement("canvas");
  // 设置画布的宽度
  canvas.width = 150;
  // 设置画布的高度
  canvas.height = 120;
  // 设置画布的显示方式
  canvas.style.display = "none";
  // 获取画布的2D绘图上下文
  var ctx = canvas.getContext("2d");
  // 旋转画布
  ctx.rotate((-20 * Math.PI) / 180);
  // 移动画布的位置
  ctx.translate(-50, 20);
  // 设置画布的填充颜色
  // ctx.fillStyle = "#f5f5f5";
  ctx.fillStyle = "red";
  // 设置画布的字体
  ctx.font = "100 16px Microsoft YaHei";
  // 绘制文本
  ctx.fillText("憋鬼叫好不好垃圾!!!", canvas.width / 2, canvas.height / 2);
  // 返回画布
  return canvas;
}

// 为canvas设置水印
function setWatermark(canvas) {
  // 创建一个div元素
  var watermark = document.createElement("div");
  // 设置div元素的样式
  const styleStr = `
        position:fixed;
        top:0;
        left:0;
        width:100vw;
        height:100vh;
        z-index:99;
        pointer-events:none;
        background-repeat:repeat;
        mix-blend-mode: multiply;
        background-image:url('${canvas.toDataURL("image/png")}')`;
  // 为div元素设置样式
  watermark.setAttribute("style", styleStr);
  // 为div元素设置id
  watermark.setAttribute("id", "watermark");
  // 将div元素添加到body中
  document.body.appendChild(watermark);
  return styleStr;
}

function setObserverForWatermark() {
  const canvas = buildWatermark();
  let styleStr = setWatermark(canvas);
  let canvasDOM = document.querySelector("#watermark");
  const bodyDOM = document.querySelector("body");

  function callback(mutationList, observer) {
    console.log(observer);
    mutationList.forEach((mutation) => {
      if (mutation.type === "attributes") {
        if (mutation.attributeName === "style") {
          // 这里需要这样判断,因为每一次修改都会触发这个回调,如果不这样判断
          // 就会导致死循环。
          if (
            !(
              mutation.target
                .getAttribute("style")
                .replaceAll(" ", "")
                .replaceAll(/\n/g, "") ===
              styleStr.replaceAll(" ", "").replaceAll(/\n/g, "")
            )
          ) {
            mutation.target.setAttribute("style", styleStr);
          }
          // 这里需要这样判断,因为每一次修改都会触发这个回调,如果不这样判断
          // 就会导致死循环。
        } else if (mutation.attributeName === "id") {
          if (mutation.target.getAttribute("id") !== "watermark") {
            mutation.target.setAttribute("id", "watermark");
          }
        } else if (mutation.attributeName === "class") {
          // 如果用户添加了class,这里主要为防止用户时候浏览器的隐藏元素选项来隐藏元素
          // 这个隐藏元素按是添加了一个class,使用overflow:hidden;来隐藏元素
          if (
            mutation.target.getAttribute("class") !== "" ||
            mutation.target.getAttribute("class") !== undefined
          ) {
            // 移除class
            mutation.target.removeAttribute("class");
          }
        }
      }
    });
  }

  // 如果元素被删除,监听元素自身是无法获取到被删除的信息的
  // 但是当子元素被删除的时候,监听父元素的mutationObserver是可以监听到的
  function parentCallback(mutationList) {
    console.log(mutationList);
    mutationList.forEach((mutation) => {
      if (mutation.type === "childList" && mutation.removedNodes.length > 0) {
        mutation.removedNodes.forEach((node) => {
          if (node === canvasDOM) {
            // 如果被删除的是水印节点,重新添加!
            setWatermark(canvas);
            canvasDOM = document.querySelector("#watermark");
          }
        });
      }
    });
  }
  // 监听DOM变化
  const observer = new MutationObserver(callback);
  observer.observe(canvasDOM, {
    attributes: true,
    childList: true,
    subtree: true,
  });

  // 监听父元素,因为当删除元素自身的时候无法被监听到,而复原可以监听子元素被删除
  const parentObserver = new MutationObserver(parentCallback);
  parentObserver.observe(bodyDOM, {
    attributes: true,
    childList: true,
    subtree: true,
  });
}

// 开始监听
setObserverForWatermark();
新手上路,请多包涵

image.png
image.png

<template>
  <div id="app">
    <canvas ref="watermarkCanvas" :style="{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%' }"></canvas>
    <!-- 页面其他内容 -->
  </div>
</template>

<script>
export default {
  data() {
    return {
      canvasWidth: window.innerWidth,
      canvasHeight: window.innerHeight,
    };
  },
  mounted() {
    this.initWatermark();
    window.addEventListener('resize', this.handleResize);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize);
  },
  methods: {
    initWatermark() {
      const canvas = this.$refs.watermarkCanvas;
      const ctx = canvas.getContext('2d');

      // 设置canvas尺寸与窗口一致
      canvas.width = this.canvasWidth;
      canvas.height = this.canvasHeight;

      // 水印配置
      const watermarkText = '通义灵码';
      const fontSize = 24;
      const color = '#ccc';
      const stepX = 200; // 水印在x轴方向的间隔
      const stepY = 200; // 水印在y轴方向的间隔

      for (let x = 0; x <= canvas.width; x += stepX) {
        for (let y = 0; y <= canvas.height; y += stepY) {
          this.drawText(ctx, watermarkText, x, y, fontSize, color);
        }
      }
    },
    drawText(context, text, x, y, fontSize, color) {
      context.font = `${fontSize}px Arial`;
      context.fillStyle = color;
      context.rotate(Math.PI / 4); // 可选:旋转水印文字(此处为45度)
      context.fillText(text, x, y);
      context.rotate(-Math.PI / 4); // 还原旋转角度
    },
    handleResize() {
      this.canvasWidth = window.innerWidth;
      this.canvasHeight = window.innerHeight;
      this.initWatermark();
    },
  },
};
</script>

image.png

在Vue管理后台中添加一个显示登录人名字背景水印的功能,可以通过以下几种方法实现:

方法一:使用CSS伪元素

  1. 定义水印样式:在你的全局样式表(如app.cssstyles.css)中,添加一个伪元素来创建水印。
body::before {
  content: "登录人名字"; /* 这里填入实际的登录人名字 */
  position: fixed;
  bottom: 10px; /* 根据需要调整位置 */
  right: 10px; /* 根据需要调整位置 */
  color: rgba(0, 0, 0, 0.1); /* 水印文字颜色,可以使用透明色 */
  font-size: 24px; /* 水印文字大小 */
  pointer-events: none; /* 忽略鼠标事件 */
  z-index: -1; /* 确保水印在内容下方 */
}
  1. 获取登录人名字:在你的Vue组件中,可以使用localStorageVuex来存储和获取登录人的名字。
export default {
  name: 'Dashboard',
  created() {
    const userName = localStorage.getItem('userName');
    if (userName) {
      // 将用户名设置为全局样式的变量
      document.body.style.setProperty('--userName', userName);
    }
  }
}

方法二:使用Vue组件

  1. 创建水印组件:创建一个Vue组件来管理水印的显示和位置。
<template>
  <div class="watermark">
    {{ userName }}
  </div>
</template>

<script>
export default {
  name: 'Watermark',
  props: {
    userName: String
  }
}
</script>

<style scoped>
.watermark {
  position: fixed;
  bottom: 10px;
  right: 10px;
  color: rgba(0, 0, 0, 0.1);
  font-size: 24px;
  pointer-events: none;
  z-index: 100;
}
</style>
  1. 在需要的页面引入水印组件:在你的Vue页面组件中引入水印组件,并传入登录人的名字。
<template>
  <div>
    <!-- 其他内容 -->
    <watermark :userName="userName" />
  </div>
</template>

<script>
import Watermark from '@/components/Watermark.vue';

export default {
  components: {
    Watermark
  },
  data() {
    return {
      userName: localStorage.getItem('userName')
    };
  }
}
</script>

方法三:使用Vue插件

  1. 创建Vue插件:创建一个Vue插件来全局添加水印。
function watermarkPlugin(Vue, userName) {
  Vue.prototype.$watermark = {
    setWatermark: function (name) {
      const style = document.createElement('style');
      style.innerHTML = `
        body::after {
          content: "${name || '登录人名字}";
          position: fixed;
          bottom: 10px;
          right: 10px;
          color: rgba(0, 0, 0, 0.1);
          font-size: 24px;
          pointer-events: none;
          z-index: 100;
        }
      `;
      document.head.appendChild(style);
    }
  };
}

export default watermarkPlugin;
  1. 在Vue实例中使用插件:在你的入口文件(如main.js)中使用插件,并传入登录人的名字。
import Vue from 'vue';
import App from './App.vue';
import watermarkPlugin from './watermarkPlugin';

Vue.use(watermarkPlugin, localStorage.getItem('userName'));

new Vue({
  render: h => h(App)
}).$mount('#app');

以上方法可以根据你的项目需求和个人喜好选择使用。记得在实际部署时,要确保登录人的名字是安全地从后端获取,而不是硬编码在代码中。

见到有个插件里面有水印,可以试试
水印插件

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏