前言:图片水印这个东西相信大家都不陌生,前端实现的方式方法也有很多,现在网上流行的无非就是种,一种是纯CSS写,另外一种就是用Canvas。
1.CSS版本
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS水印示例</title>
<style>
.water_mark {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
pointer-events: none;
opacity: 0.8;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-size="30" fill="rgba(0,0,0,0.3)">女神刘亦菲~</text></svg>') repeat;
}
</style>
</head>
<body>
<!-- 水印 -->
<div class="water_mark"></div>
<img src="./img/lyf.jpg" style="width:100%;height:100vh">
</body>
</html>
效果如下:

优点:
- 实现简单
- 代码易读性强,适合入门级新手。
缺点:
- 可以在浏览器的控制台修改water_mark类样式,如果设置为display:none。水印就去掉了
- "水印文本"这几个字不灵活,不好复用。
2.Canvas版本
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas水印示例</title>
<style>
* {
margin: 0;
padding: 0
}
.watermark {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
pointer-events: none;
opacity: 0.2;
}
</style>
</head>
<body>
<canvas id="watermarkCanvas" class="watermark"></canvas>
<img src="./img/lyf.jpeg" style="width:100%;height:100vh">
<script>
function watermark(text) {
var canvas = document.getElementById('watermarkCanvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var width = canvas.width;
var height = canvas.height;
ctx.font = '30px Arial';
ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// 旋转并重复绘制水印文本
for (var x = 0; x < width; x += 200) {
for (var y = 0; y < height; y += 200) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(- Math.PI / 4);
ctx.fillText(text, 0, 0);
ctx.restore();
}
}
}
window.onload = function () {
watermark('我爱女神刘亦菲~')
};
</script>
</body>
</html>
效果如下:

优点:
- 封装一个JS方法能很好的代码复用。
- 后续如果扩展,文本样式也可以通过参数的形式传入。
缺点:
- dom结构不复杂的情况下,在控制台审查元素还是很容易找到dom结构把它隐藏掉。
- 要学习canvas
3.终极版本vue3指令版
js
//入口文件main.js
import { watermark } from '@/watermark.js'
const setupAll = async () => {
const app = createApp(App)
//...省略
watermark(app) //全局注册
app.mount('#app')
}
setupAll()
js
//组件里面使用
<img src="@/assets/imgs/lyf.png" v-watermark="'我爱女神刘亦菲'" alt="">
js
export function watermark(app) {
app.directive('watermark', (el, binding) => {
const watermarkText = binding.value || '默认水印';
const fontSize = 24;
const fillStyle = 'rgba(0, 0, 0, 0.2)';
const angle = 45;
const distance = 200;
if (el.tagName !== 'IMG') {
console.warn('v-watermark should be applied on <img> element.');
return;
}
const img = el;
const processImage = () => {
if (el._watermarkProcessed) return;
el._watermarkProcessed = true;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制原始图片
ctx.drawImage(img, 0, 0);
// 设置水印样式
ctx.font = `${fontSize}px Arial`;
ctx.fillStyle = fillStyle;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const radianAngle = (angle * Math.PI) / 180;
for (let x = -canvas.width; x < canvas.width * 2; x += distance) {
for (let y = -canvas.height; y < canvas.height * 2; y += distance) {
ctx.save();
ctx.translate(x + canvas.width / 2, y + canvas.height / 2);
ctx.rotate(radianAngle);
ctx.fillText(watermarkText, 0, 0);
ctx.restore();
}
}
img.src = canvas.toDataURL('image/png');
};
if (img.complete && img.naturalWidth > 0) {
processImage();
} else {
img.addEventListener('load', processImage);
}
});
}
效果如下:

优点:
- 使用简单
- 方便复用
- 防篡改
总结:
怎么样兄弟们,如果该文章对你有帮助,就请点赞+收藏吧!如果你们项目中也有这种需求。你会使用哪种方式去做呢?欢迎留言讨论~