利用 canvas / svg 实现水印
个人组件网站:https://luoheix.github.io/watermark
利用 canvas 实现(2020-08-03)
利用 canvas 标签生成图片,作为页面元素的背景图来实现水印效果。
js中的实现
效果
代码
(水印位置自行设置)
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title>Document</title>
<style>
</style>
</head>
<body>
<script>
function getCanvasUrl(text, fontSzie, color, width = 500, height = 300) {
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
context.font = fontSzie + 'px Arial';
context.fillStyle = color;
context.textAlign = "center";
context.textBaseline = "middle";
context.rotate(Math.PI / 180 * -30); // 旋转
context.fillText(text, 130, 250); // 填充文本,设置位置
var base64Url = canvas.toDataURL('image/png'); // 生成url
return base64Url;
}
const text = `${(new Date()).toLocaleDateString()} 用户名用户名`;
var watermarkDiv = document.createElement('div');
watermarkDiv.setAttribute('style', `
position:fixed;
top:0;
left:0;
z-index:9999;
width:100%;
height:100%;
opacity: 0.1;
pointer-events:none;
background-repeat:repeat;
background-image:url('${getCanvasUrl(text, 28, 'rgb(128,128,128)')}')
`);
document.body.appendChild(watermarkDiv);
</script>
</body>
</html>
设置行内样式缺陷
canvas生成路径会很长,直接设置行内样式会在页面上占据很大空间。
react 中利用 style-it
页面效果
html效果
css效果
代码
import React, { useState, useEffect } from 'react';
import Style from 'style-it';
// 生成水印背景图地址
const getCanvasUrl = (text = '用户名用户名', width = 500, height = 300, fontSize = 28, color = 'rgb(128,128,128)') => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
context.font = fontSize + 'px Arial';
context.fillStyle = color;
context.textAlign = "center";
context.textBaseline = "middle";
context.rotate(Math.PI / 180 * -30);
context.fillText(`${(new Date()).toLocaleDateString()} ${text}`, 130, 250);
return canvas.toDataURL('image/png');
};
const Index = props => {
const [canvasUrl, setCanvasUrl] = useState('');
useEffect(() => {
setCanvasUrl(getCanvasUrl());
}, []);
return (
<Style>
{`
.watermark {
position:fixed;
top:0;
left:0;
z-index:9999;
width:100%;
height:100%;
opacity: 0.1;
pointer-events:none;
background-repeat:repeat;
background-image:url('${canvasUrl}')
}
`}
<div className="watermark"></div>
</Style>
);
};
export default Index;
利用 svg 实现“更简单、性能更高”(2020-11-04)
生成 svg 标签,直接作为页面元素的背景图来实现水印效果。
特点:无需生成图片,可直接内嵌在 html 中或直接作为背景图使用。
效果
style
index.jsx
注意:svg 作为图片或浏览器直接打开必须转义,且需定义 xmlns="http://www.w3.org/2000/svg"。如果内嵌到html标签中则不需要。(最佳 svg 转义方式)
import React, { useState, useEffect } from 'react';
// 因为安全原因 svg 需转译以便作为背景图使用,也可直接在浏览器中打开
// 因为要保留 xvg 可读性,所以使用自定义方法进行转义
const svgToUrl = str => {
return `data:image/svg+xml,${str
.replace(/\n/g, '')
.replace(/<!--(.*)-->/g, '') // 必须去掉注释
.replace(/[\r\n]/g, ' ') // 最好去掉换行
.replace(/"/g, "'") // 单引号是保留字符,双引号改成单引号减少编码
.replace(/%/g, '%25')
.replace(/&/g, '%26')
.replace(/#/g, '%23')
.replace(/{/g, '%7B')
.replace(/}/g, '%7D')
.replace(/</g, '%3C')
.replace(/>/g, '%3E')}`;
};
/**
* 生成 svg 字符串
* @param {object} options 参数
* text 水印文字
* <text> 属性(x y transform) 方向位置按需调整
* <svg> 中fill属性决定字体颜色
*/
const getCanvasUrl = options => {
const {
text = `${new Date().toLocaleDateString()} Svg生成水印`,
width = 500,
height = 300,
fontSize = 28,
color = 'rgb(128,128,128)',
fontFamily = 'inherit',
} = options || {};
return `<svg
width="${width}"
height="${height}"
fill="${color}"
xmlns="http://www.w3.org/2000/svg"
>
<text
x="38%"
y="77%"
transform="rotate(-35, 100 100)"
font-size="${fontSize}"
font-family="${fontFamily}"
text-anchor="middle"
dominant-baseline="middle"
>${text}</text>
</svg>`;
};
const WatermarkSvg = () => {
const [svgUrl, setSvgUrl] = useState('');
useEffect(() => {
const newSvgUrl = svgToUrl(getCanvasUrl());
setSvgUrl(newSvgUrl);
}, []);
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
zIndex: 9999,
width: '100%',
height: '100%',
opacity: 0.2,
pointerEvents: 'none',
background: `url("${svgUrl}") repeat`,
}}
/>
);
};
export default WatermarkSvg;