vue2添加背景水印-手动实现(无组件模式)

1. App.vue

javascript 复制代码
<template>
  <div id="app" class="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  mounted() {
    this.updateWatermark();
    // 监听路由变化
    this.$router.afterEach(() => {
      this.$nextTick(() => {
        this.ensureWatermarkAndTable();
      });
    });
    // 监听 DOM 变化,确保表格背景实时调整
    this.observeDOM();
  },
  data() {
    return {
      watermarkText: "",
      user: {},
    };
  },
  methods: {
    updateWatermark() {
      let curUser = sessionStorage.getItem("curUser");
      if (curUser) {
        try {
          const userData = JSON.parse(curUser);
          this.watermarkText = `${userData.systemUsers.nickname}(${userData.systemRoleList[0].name})`;
        } catch (e) {
          console.error("解析 curUser 失败:", e);
          this.watermarkText = "默认水印"; // 备用文本
        }
      } else {
        this.watermarkText = "默认水印"; // 无用户数据时使用默认值
      }
      console.log("水印文本:", this.watermarkText);
      this.addWatermark();
    },
    addWatermark() {
      const oldWatermark = document.querySelector(".watermark-layer");
      if (oldWatermark) oldWatermark.remove();

      const canvas = document.createElement("canvas");
      canvas.width = 200;
      canvas.height = 200;
      const ctx = canvas.getContext("2d");
      ctx.font = "16px Arial";
      ctx.fillStyle = "rgba(102, 102, 102, 0.5)";
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.rotate((-20 * Math.PI) / 180);
      ctx.fillText(this.watermarkText, canvas.width / 2, canvas.height / 2);
      const dataURL = canvas.toDataURL();

      const watermarkLayer = document.createElement("div");
      watermarkLayer.className = "watermark-layer";
      watermarkLayer.style.backgroundImage = `url(${dataURL})`;
      watermarkLayer.style.backgroundRepeat = "repeat";
      document.body.appendChild(watermarkLayer);
    },
    ensureWatermarkAndTable() {
      if (!document.querySelector(".watermark-layer")) {
        this.addWatermark();
      }
      this.adjustTableBackground();
    },
    adjustTableBackground() {
      const tables = document.querySelectorAll(".el-table");
      tables.forEach((table) => {
        table.style.backgroundColor = "rgba(255, 255, 255, 0.8)";
        const wrappers = table.querySelectorAll(".el-table__body-wrapper, .el-table__header-wrapper, .el-table__fixed, .el-table__fixed-right");
        wrappers.forEach((wrapper) => {
          wrapper.style.backgroundColor = "rgba(255, 255, 255, 0.8)";
        });
        const cells = table.querySelectorAll("th, td, tr");
        cells.forEach((cell) => {
          cell.style.backgroundColor = "transparent";
        });
      });
    },
    observeDOM() {
      const observer = new MutationObserver(() => {
        this.ensureWatermarkAndTable();
      });
      observer.observe(document.body, {
        childList: true,
        subtree: true,
      });
    },
  },
};
</script>

<style>
.app {
  width: 100vw;
  height: 100vh;
  position: relative;
  z-index: 1;
  color: #333;
}

.watermark-layer {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;
}

body {
  margin: 0;
  padding: 0;
  position: relative;
}

html,
body,
h3,
p {
  margin: 0;
  padding: 0;
}
</style>

2. src/assets/css/main.css

javascript 复制代码
/* src/assets/css/main.css */
.el-table,
.el-table__body-wrapper,
.el-table__header-wrapper,
.el-table__fixed,
.el-table__fixed-right,
.el-table__body,
.el-table__header {
  background-color: rgba(255, 255, 255, 0.8) !important;
}

.el-table th,
.el-table tr,
.el-table td,
.el-table__cell {
  background-color: transparent !important;
}

.watermark-layer {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0 !important;
  pointer-events: none;
}

3. main.js

javascript 复制代码
import Vue from "vue";
import App from "./App.vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import router from "./router/index";
import store from "./store/index";
import * as echarts from "echarts";
import JsonViewer from "vue-json-viewer";
import VueCron from "vue-cron";
import VideoPlayer from "vue-video-player/src";
import "vue-video-player/src/custom-theme.css";
import "video.js/dist/video-js.css";
import "./assets/css/content.css";
import "./assets/css/main.css"; // 确保引入

Vue.prototype.$echarts = echarts;
Vue.use(JsonViewer);
Vue.use(VueCron);
Vue.use(VideoPlayer);
Vue.use(ElementUI);

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: (h) => h(App),
  created() {
    store.commit("addMenu", router);
  },
}).$mount("#app");

4.实现效果

相关推荐
Ai-_Man4 分钟前
您您这可以把Google AI Studio的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
两个西柚呀14 分钟前
JS事件总结
前端·javascript·css
小狼1545418 分钟前
拼多多订单数据导出 CSV 实战:接口分页、字段平铺与 5 个数据坑,多多开票助手
java·前端·javascript
搬砖的小码农_Sky27 分钟前
AI Agent:Node.js和浏览器运行环境的本质区别
javascript·node.js·人机交互
ss27340 分钟前
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁
前端·vue.js·react.js
想吃火锅100541 分钟前
【leetcode】189.轮转数组js
开发语言·javascript·leetcode
天衍四九-44 分钟前
Docker Compose企业实战系列(三):Vue/React前端项目容器化完整部署
前端·vue.js·docker
墨鱼老师1 小时前
SpringBoot+Vue 毕设项目开发踩坑记录(前后端分离)
vue.js·spring boot·毕业设计·课程设计·前后端分离·java 毕设
雪芽蓝域zzs2 小时前
Vue3 + Element Plus el-select 下拉弹窗
vue.js·elementui
Wx-bishekaifayuan2 小时前
springboot房屋租赁系统11574-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·sql·spring·课程设计