Open xuanweiH opened 3 years ago
增加了水印的防修改功能 优化了之前的版本
// 首先定义一个接口类 限制options的类型
export interface WaterMarkOption {
width?: string;
height?: string;
textAlign?: CanvasTextAlign;
textBaseline?: CanvasTextBaseline;
font?: string;
fillStyle?: string;
content?: string;
rotate?: number;
zIndex?: number;
}
// 创建一个cavas对象来画水印
async function getWatermarkDom({
width = "100px",
height = "100px",
textAlign = "center",
textBaseline = "middle",
font = "20px microsoft yahei",
fillStyle = "rgba(184, 184, 184, 0.1)",
content = "请勿外传",
rotate = 30,
zIndex = 9999
}: WaterMarkOption = {}) {
const canvas = document.createElement("canvas");
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.save();
ctx.textAlign = textAlign;
ctx.textBaseline = textBaseline;
ctx.font = font;
ctx.fillStyle = fillStyle;
// 把画的图像稍微翻转一下角度
ctx.translate(parseFloat(width) / 2, parseFloat(height) / 2);
ctx.rotate((Math.PI / 180) * rotate);
ctx.translate(-parseFloat(width) / 2, -parseFloat(height) / 2);
ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);
ctx.translate(parseFloat(width) / 2, parseFloat(height) / 2);
ctx.rotate((-Math.PI / 180) * rotate);
ctx.translate(-parseFloat(width) / 2, -parseFloat(height) / 2);
// restore() 方法从栈中弹出存储的图形状态并恢复 CanvasRenderingContext2D 对象的属性
ctx.restore();
// cavas画好以后转为blob再获取url
const getUrl = () =>
new Promise(resolve => {
canvas.toBlob(blob => {
resolve(window.URL.createObjectURL(blob));
});
});
const waterMarkUrl = await getUrl();
const renderWaterMarkDiv = document.createElement("div");
renderWaterMarkDiv.id = window.btoa("water-mark_" + Date.now());
renderWaterMarkDiv.setAttribute(
"style",
`
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:${zIndex};
pointer-events:none;
background-repeat:repeat;
background-image:url('${waterMarkUrl}')`
);
return renderWaterMarkDiv;
}
// 完成绘制以后再来一个防修改处理
function securityDefense(target) {
// 把canvas画好的div导入
document.body.appendChild(target);
const callback = function(records) {
// 如果有相关操作先移除target 再添加回来防止删除
if (
records.length === 1 &&
((records[0].target === target && records[0].attributeName === "style") ||
(records[0].removedNodes.length >= 1 &&
records[0].removedNodes[0] === target))
) {
if (records[0].attributeName === "style") {
document.body.removeChild(target);
}
bodyObserver.disconnect();
domObserver.disconnect();
setTimeout(() => createWaterMark(), 0);
}
};
// 先创建一个全局观察者 观察body的子标签 防止用户直接去element里面删除
const MutationObserver = window.MutationObserver;
const bodyObserver = new MutationObserver(callback);
bodyObserver.observe(document.body, {
childList: true
});
// 再创建一个目标节点观察者,观察是否修改style属性
const domObserver = new MutationObserver(callback);
domObserver.observe(target, { attributes: true, attributeFilter: ["style"] });
}
let _option = {};
export default function createWaterMark(options?: WaterMarkOption) {
_option = options ? options : _option;
getWatermarkDom(_option).then(securityDefense);
}
--------------------
vuex user.js中
import createWaterMark from "@/utils/waterMark";
// 把userid作为背景当做水印
SET_USER_DATA(state, data) {
createWaterMark({ content: data.uid });
localStorage.setItem(USER_DATA_KEY, JSON.stringify(data));
state.data = data;
},
话不多说直接上代码: