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

js实现的前端水印

效果
在这里插入图片描述

var defaultConfig = {content: [], // 水印内容数组fontSize: 14, // 字体大小(px)fontFamily: 'sans-serif', // 字体color: 'rgba(255, 255, 255,.3)', // 字体颜色rotate: -20, // 旋转角度(度数)zIndex: 2147483647, // 层级globalAlpha: 0.5, // 透明度canvasWidth: 300, // 单个水印canvas宽度canvasHeight: 200, // 单个水印canvas高度textAlign: 'left', // 文本对齐方式top: 30, // 上边距left: 50, // 左边距container: document.body, // 挂载容器monitor: true //是否开启监控
}function Watermark(options) {if (Watermark.instance) {Watermark.instance.destroy()}if (typeof options.content === 'string') {var timestamp = formatTime(new Date())options.content = [options.content, timestamp]}this.config = mergeObjects({}, defaultConfig, options || {})this.observers = []this.canvas = nullthis.watermarkDiv = nullWatermark.instance = thisthis.init()
}Watermark.prototype.init = function () {this.createCanvas()this.applyWatermark()
}Watermark.prototype.createCanvas = function () {var config = this.configvar canvas = document.createElement('canvas')var ctx = canvas.getContext('2d')canvas.width = config.canvasWidthcanvas.height = config.canvasHeightctx.save()try {ctx.font = config.fontSize + 'px ' + config.fontFamilyctx.fillStyle = config.colorctx.globalAlpha = config.globalAlphactx.textAlign = config.textAlignvar centerX = canvas.width / 2var centerY = canvas.height / 2ctx.translate(centerX, centerY)ctx.rotate((config.rotate * Math.PI) / 180)ctx.translate(-centerX, -centerY)var lineHeight = config.fontSize * 1.5var startY = (canvas.height - config.content.length * lineHeight) / 2config.content.forEach(function (text, index) {ctx.fillText(text, config.left, startY + index * lineHeight + config.top)})} finally {ctx.restore()}this.canvas = canvas
}Watermark.prototype.applyWatermark = function () {var config = this.configvar container = this.getContainer()var isBodyContainer = container === document.body // 判断是否为body容器// 创建水印层var dom = document.createElement('div')dom.style.position = isBodyContainer ? 'fixed' : 'absolute'dom.style.top = '0'dom.style.left = '0'dom.style.width = '100%'dom.style.height = '100%'dom.style.pointerEvents = 'none'dom.style.zIndex = config.zIndexdom.style.backgroundImage = 'url(' + this.canvas.toDataURL() + ')'dom.style.backgroundRepeat = 'repeat'// 处理容器定位if (!isBodyContainer &&window.getComputedStyle &&window.getComputedStyle(container).position === 'static') {container.style.position = 'relative'}this.destroyInternal()this.watermarkDiv = domcontainer.appendChild(dom)// 防止篡改if (this.config.monitor) {this.setupMutationObserver()}
}Watermark.prototype.getContainer = function () {var container = this.config.containerif (typeof container === 'string') {return document.querySelector(container) || document.body}return container || document.body
}Watermark.prototype.setupMutationObserver = function () {var self = thisif (typeof MutationObserver === 'undefined') return// 水印节点监听var primaryObserver = new MutationObserver(function (mutations) {mutations.forEach(function (mutation) {if (mutation.type === 'attributes') {self.applyWatermark()}})})primaryObserver.observe(this.watermarkDiv, {attributes: true,attributeFilter: ['style', 'class'],childList: false,subtree: false})// 父节点监听var guardianObserver = new MutationObserver(function (mutations) {mutations.forEach(function (mutation) {if (mutation.removedNodes && mutation.removedNodes.length > 0) {if ([].some.call(mutation.removedNodes, function (node) {return node === self.watermarkDiv})) {self.applyWatermark()}}})})guardianObserver.observe(this.watermarkDiv.parentNode, {childList: true,subtree: false})this.observers.push(primaryObserver, guardianObserver)
}Watermark.prototype.destroy = function () {this.destroyInternal()Watermark.instance = null
}Watermark.prototype.destroyInternal = function () {// 移除水印元素if (this.watermarkDiv && this.watermarkDiv.parentNode) {this.watermarkDiv.parentNode.removeChild(this.watermarkDiv)}// 停止观察this.observers.forEach(function (observer) {observer.disconnect()})this.observers = []
}// 对象合并方法(浅拷贝)
function mergeObjects(target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i]for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key]}}}return target
}// 日期格式化
function formatTime(date) {var year = date.getFullYear()var month = date.getMonth() + 1var day = date.getDate()var hours = date.getHours()var minutes = date.getMinutes()var seconds = date.getSeconds()month = month < 10 ? '0' + month : monthday = day < 10 ? '0' + day : dayhours = hours < 10 ? '0' + hours : hoursminutes = minutes < 10 ? '0' + minutes : minutesseconds = seconds < 10 ? '0' + seconds : secondsreturn year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}export default Watermark

Vue3集成方式

import Watermark from "@/utils/watermark.esm.js";// 初始化水印
const watermark = ref(null);
onMounted(() => {watermark.value = new Watermark ({content: "张三"});
});// 销毁水印(可选)
onBeforeUnmount(() => {watermark.value?.destroy();
});```

相关文章:

  • 人工智能代理重塑数字成功:为何面向机器的营销是下一前沿
  • OOM 未触发 JVM 崩溃的可能原因
  • 如何-批量修改文件夹的命名
  • FPGA-VGA
  • Android——动画
  • Node.js 异步调用淘宝 API 实践:高吞吐商品详情数据采集方案
  • 双层Key缓存
  • 010301-cdn_waf-web扩展1-基础入门-网络安全
  • [密码学实战]国密算法面试题解析及应用
  • 使用Python绘制AUC曲线(即ROC曲线)
  • 极狐GitLab 用户 API 速率限制如何设置?
  • 【java 13天进阶Day12】XML和Dom4j,装饰模式,工厂模式,commons-io工具包,Base64
  • 机器学习05-CNN
  • C# 高级编程:Lambda 表达式
  • PHP腾讯云人脸核身获取Access Token
  • 《软件设计师》复习笔记(11.6)——系统转换、系统维护、系统评价
  • ASP.NET MVC 实现增删改查(CRUD)操作的完整示例
  • 给予FLUX更好的控制:FLUX.1-dev-ControlNet-Union-Pro-2.0
  • 精准计量+AI管控——安科瑞助力高校水电管理数字化转型
  • 2025妈妈杯数学建模D题完整分析论文
  • 观察|中日航线加速扩容,航空公司如何抓住机会?
  • 广西东兰官方通报“村民求雨耕种”:摆拍,恶意炒作
  • 摩根大通首席执行官:贸易战损害美国信誉
  • 42岁北京大学科学技术与医学史系副教授陈昊逝世
  • 租到“甲醛房”,租客可以解约吗?租金能要回来吗?
  • 坚定信心主动应变局谋发展,上海市领导走访调研外资外贸企业