当前位置: 首页 > news >正文

vue3 实现前端生成水印效果

vue3 实现前端生成水印效果

首先一点哈,就是单纯web前端生成水印只能作为警示使用,如果享彻底防住几乎是不可能的,有无数种方式去掉web前端生成的水印,所以这种方式只当是一个君子协议吧。

编写水印组件

首先直接把这部分封装成一个组件吧,我这边直接上代码了。

创建一个 waterMark.vue 文件,用来编写水印组件:

<template><div class="watermark-container" ref="parentRef"><slot></slot></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import useWaterMarkBg from './waterMarkBg';
const props = defineProps({text: {type: String,default: "版权所有"},fontSize: {type: Number,default: 25,},gap: {type: Number,default: 20,},color: {type: String,default: 'rgba(201, 35, 35, 0.5)'}
})let div;
const bg = useWaterMarkBg(props);
const parentRef = ref();const ob = new MutationObserver((entries) => {for (const entry of entries) {for (const node of entry.removedNodes) {if (node === div) {resetWatermark();return;}}if (entry.target === div) {resetWatermark();}}
})onMounted(() => {resetWatermark();ob.observe(parentRef.value, {childList: true,subtree: true,attributes: true,})
})onUnmounted(() => {ob.disconnect();
})// 重置水印
const resetWatermark = () => {if (!parentRef.value) { return }if (div) {div.remove();}const { base64, size } = bg.value.value;div = document.createElement('div');div.style.position = 'absolute';div.style.backgroundImage = `url(${base64})`;div.style.backgroundSize = `${size.width}px ${size.height}px`;div.style.backgroundRepeat = "repeat";div.style.pointerEvents = 'none';div.style.zIndex = '9999';div.style.inset = 0;parentRef.value.appendChild(div);
}</script>
<style scoped lang="scss">
.watermark-container {position: relative;
}
</style>

可以接受四个参数,如果不够可以自己加,分别是 text 水印文本内容fontSize 水印文本大小gap 水印文本间隔color 水印文本颜色

然后在水印组件加载完成的时候调用 resetWatermark 重置水印方法实现添加水印。

水印是动态生成的图片,最后创建了一个动态的div加上页面的,因为还想尽可能的防止一下水印删除,所以说在中途检测了一下dom修改情况,如果修改了,比如删除了div,或者是修改了div的样式,那么就重置水印,重新添加一遍。

其中在组件中还是用了 useWaterMarkBg 方法,下面代码是 waterMarkBg.js 文件的内容,可以根据自己的业务需求适当的修改:

import { ref, computed } from 'vue';/*** 创建水印背景图片的 composable 函数* @param {Object} options - 水印配置选项* @param {string} options.text - 水印文字内容* @param {number} options.fontSize - 字体大小* @param {number} options.gap - 水印间隔* @param {string} options.color - 文字颜色,默认为半透明灰色* @param {number} options.rotate - 旋转角度,默认为 -15 度* @param {string} options.fontFamily - 字体,默认为 Arial* @returns {Object} 返回包含 base64 和 size 的响应式对象*/
function useWaterMarkBg(options = {}) {// 默认参数const defaultOptions = {text: '版权所有',fontSize: 25,gap: 20,color: 'rgba(201, 35, 35, 0.5)',rotate: -15,fontFamily: 'Arial, sans-serif'};// 合并用户参数和默认参数const waterMarkOptions = ref({ ...defaultOptions, ...options });// 计算水印尺寸和 base64 图片const waterMarkInfo = computed(() => {const { text, fontSize, gap, color, rotate, fontFamily } = waterMarkOptions.value;// 创建 canvas 元素const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');if (!ctx) {throw new Error('无法获取 canvas 上下文');}// 设置字体ctx.font = `${fontSize}px ${fontFamily}`;// 获取文字宽度const textWidth = ctx.measureText(text).width;// 计算 canvas 尺寸(包含文字和间隙)const width = textWidth + gap * 2;const height = fontSize * 2 + gap * 2;canvas.width = width;canvas.height = height;// 重置上下文(因为 canvas 尺寸改变了)ctx.font = `${fontSize}px ${fontFamily}`;ctx.fillStyle = color;ctx.textAlign = 'center';ctx.textBaseline = 'middle';// 保存当前状态ctx.save();// 移动到 canvas 中心并旋转ctx.translate(width / 2, height / 2);ctx.rotate((Math.PI / 180) * rotate);// 绘制文字ctx.fillText(text, 0, 0);// 恢复之前的状态ctx.restore();// 转换为 base64const base64 = canvas.toDataURL('image/png');return {base64,size: {width,height}};});// 如果传入的 options 发生变化,可以更新水印function updateOptions(newOptions) {waterMarkOptions.value = { ...waterMarkOptions.value, ...newOptions };}return {value: waterMarkInfo,updateOptions};
}export default useWaterMarkBg;

水印组件的使用

使用的时候就很简单了,引入一下,然后包裹一下需要添加水印的dom就可以了:

    <!-- 默认红色水印 --><water-mark text="严禁传播"><div class="img-con"><img src="../../assets/imgs/watermark/1.jpg" alt="图片1"></div></water-mark><!-- 蓝色水印 --><water-mark text="禁止复制" :fontSize="25" color="rgba(30, 144, 255, 0.3)"><div class="img-con"><img src="../../assets/imgs/watermark/2.jpg" alt="图片2"></div></water-mark><!-- 绿色水印 --><water-mark text="测试水印" :fontSize="25" color="rgba(50, 205, 50, 0.4)"><div class="img-con"><img src="../../assets/imgs/watermark/1.jpg" alt="图片3"></div></water-mark>

效果

在这里插入图片描述

好了,大体就这个样子,还是,水印这个很容易删除,懂得人,删的很快,最好从源头解决,只要后端返回前端的是原文件,那么就可以从浏览器获取到没有水印的内容。


文章转载自:

http://IaUB8paY.mLntx.cn
http://awPQ6ahb.mLntx.cn
http://JeJZUd3V.mLntx.cn
http://gEZyRGLr.mLntx.cn
http://W5hc6MK7.mLntx.cn
http://yS152yRD.mLntx.cn
http://8tjwUpAT.mLntx.cn
http://JGNHLcGh.mLntx.cn
http://7Kl8B7rI.mLntx.cn
http://dNRPoz0f.mLntx.cn
http://03atABQM.mLntx.cn
http://VdAdbWXI.mLntx.cn
http://4zi9dZqc.mLntx.cn
http://YYeCfJud.mLntx.cn
http://bCtlHoQ5.mLntx.cn
http://BXkaXlQv.mLntx.cn
http://qTH7dcyu.mLntx.cn
http://JR3Sr7J0.mLntx.cn
http://w2qMqKoi.mLntx.cn
http://HvCt2d6t.mLntx.cn
http://oNKuruB9.mLntx.cn
http://yy5ZBLJT.mLntx.cn
http://POJJIYAW.mLntx.cn
http://wsqI0KCc.mLntx.cn
http://t7mZMUVa.mLntx.cn
http://2OnQcd6F.mLntx.cn
http://Boxvbpmb.mLntx.cn
http://R71d8u9P.mLntx.cn
http://4h7ayzZM.mLntx.cn
http://Sp9lYKJR.mLntx.cn
http://www.dtcms.com/a/385636.html

相关文章:

  • 手机上有哪些比较好用的待办事项提醒工具
  • 二维前缀和:模板+题目
  • 充电宝方案开发,充电宝MCU控制方案设计
  • 多品牌摄像机视频平台EasyCVR海康大华宇视视频平台统一接入方案
  • 香港云服务器数据盘可以挂载到多个实例吗?
  • 【C语言】用程序求1!+2!+3!+4!+...n!的和,来看看?
  • 【C++】浅谈智能指针
  • 第三章 神经网络入门笔记:从概念到实践全解析
  • 20250915在荣品RD-RK3588-MID开发板的Android13系统下使用TF卡刷机
  • 四元论的正确性数学原理
  • 你的第一个AI项目部署:用Flask快速搭建模型推理API
  • MyBatis-相关知识点
  • 【Nginx开荒攻略】Nginx配置文件语法规则:从基础语法到高级避坑指南
  • 【系统分析师】2024年下半年真题:论文及解题思路
  • Linux 标准输入 标准输出 标准错误
  • 【减少丢帧卡顿——状态管理】
  • pytest 常用方法介绍
  • 牛客周赛 Round 109 (小红的直角三角形
  • 【C++实战⑬】解锁C++文件操作:从基础到实战的进阶之路
  • 股票进阶之成交量买卖法
  • 【LangChain指南】Prompt templates
  • CSS基础 - 选择器备忘录 --笔记5
  • Vue-30-利用Vue3大模型对话框设计之切换主题时显示对应的session列表
  • 全光谱 LED 太阳光模拟器的原理
  • 权限更改centos中系统文件无法创建文件夹,使用命令让普通用户具备操作文件夹
  • 【WebGIS】Vue3使用 VueLeaflet + 天地图 搭建地图可视化平台(基础用法)
  • 69-SQLite应用
  • Day06 双指针扫描 | 11. 盛最多水的容器
  • LeetCode 刷题【77. 组合、78. 子集、79. 单词搜索】
  • Jenkins 构建清理策略:自带功能 vs Discard Old Build 插件,全场景实操指南