js怎样实现水印效果

来源:开发教程作者:松本一香头衔:网络博主
导读:本期聚焦于小伙伴创作的《js怎样实现水印效果》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《js怎样实现水印效果》有用,将其分享出去将是对创作者最好的鼓励。

js实现水印效果的两种核心方案

在web开发中,使用js实现水印效果主要有两种常用思路,一种是通过canvas绘制水印内容生成图片,再将图片作为背景平铺到页面上;另一种是直接创建DOM元素,通过样式控制水印的位置和展示效果。两种方案各有适用场景,下面分别展开说明。

方案一:基于canvas生成水印背景

这种方案的核心是先使用canvas绘制出水印的文字内容,再将canvas转换为base64格式的图片,最后把这张图片设置为页面的背景并平铺,实现全页面水印覆盖。

实现步骤

  • 创建canvas元素,设置画布的宽高
  • 获取canvas的绘图上下文,设置文字的样式、颜色、旋转角度
  • 绘制水印文字到canvas上
  • 将canvas转换为base64图片地址
  • 将图片地址设置为目标容器的背景,设置背景平铺

完整代码示例

// 生成水印的方法
function createCanvasWatermark(watermarkText, targetSelector = 'body') {
    // 创建canvas元素
    const canvas = document.createElement('canvas');
    // 设置单个水印块的宽高
    canvas.width = 200;
    canvas.height = 150;
    const ctx = canvas.getContext('2d');
    // 设置文字样式
    ctx.font = '16px Microsoft YaHei';
    ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
    // 旋转画布,让文字倾斜
    ctx.rotate(-20 * Math.PI / 180);
    // 绘制水印文字
    ctx.fillText(watermarkText, 10, 80);
    // 转换为base64图片
    const base64Url = canvas.toDataURL('image/png');
    // 获取目标容器,设置背景
    const targetDom = document.querySelector(targetSelector);
    if (targetDom) {
        targetDom.style.backgroundImage = `url(${base64Url})`;
        targetDom.style.backgroundRepeat = 'repeat';
    }
}

// 调用方法,设置水印内容
createCanvasWatermark('测试水印');

方案二:直接操作DOM创建水印元素

这种方案不需要生成图片,直接创建多个包含水印文字的div元素,通过绝对定位平铺到页面上,适合需要动态调整水印内容或者水印元素需要响应交互的场景。

实现步骤

  • 计算页面可展示区域的大小,确定需要创建的水印元素数量
  • 循环创建水印div元素,设置统一的样式,包括文字、颜色、旋转、定位
  • 将所有水印元素添加到页面的容器中

完整代码示例

// 生成DOM水印的方法
function createDOMWatermark(watermarkText, targetSelector = 'body') {
    const targetDom = document.querySelector(targetSelector);
    if (!targetDom) return;
    // 获取容器宽高
    const containerWidth = targetDom.offsetWidth;
    const containerHeight = targetDom.offsetHeight;
    // 单个水印块的宽高
    const watermarkWidth = 200;
    const watermarkHeight = 150;
    // 计算需要创建的水印行数和列数
    const rowCount = Math.ceil(containerHeight / watermarkHeight);
    const colCount = Math.ceil(containerWidth / watermarkWidth);
    // 循环创建水印元素
    for (let i = 0; i < rowCount; i++) {
        for (let j = 0; j < colCount; j++) {
            const watermarkItem = document.createElement('div');
            // 设置水印样式
            watermarkItem.style.position = 'absolute';
            watermarkItem.style.left = j * watermarkWidth + 'px';
            watermarkItem.style.top = i * watermarkHeight + 'px';
            watermarkItem.style.width = watermarkWidth + 'px';
            watermarkItem.style.height = watermarkHeight + 'px';
            watermarkItem.style.fontSize = '16px';
            watermarkItem.style.fontFamily = 'Microsoft YaHei';
            watermarkItem.style.color = 'rgba(0, 0, 0, 0.1)';
            watermarkItem.style.transform = 'rotate(-20deg)';
            watermarkItem.style.pointerEvents = 'none';
            watermarkItem.style.userSelect = 'none';
            watermarkItem.innerHTML = watermarkText;
            targetDom.appendChild(watermarkItem);
        }
    }
}

// 调用方法
createDOMWatermark('测试水印');

水印防篡改实现思路

上面的基础方案实现的水印容易被用户通过开发者工具删除,要实现防篡改效果,可以添加监听逻辑:

  • 使用MutationObserver监听水印容器或者水印元素的DOM变化,一旦发现水印被删除,立即重新生成水印
  • 定时检测水印元素是否存在,不存在则重新创建
  • 将水印元素的pointer-events设置为none,避免影响页面正常交互

防篡改代码示例

// 给DOM水印添加防篡改逻辑
function addWatermarkProtect(targetSelector = 'body') {
    const targetDom = document.querySelector(targetSelector);
    if (!targetDom) return;
    // 创建MutationObserver监听DOM变化
    const observer = new MutationObserver(() => {
        // 检测水印元素是否存在,这里假设水印元素的className为watermark-item
        const watermarkList = targetDom.querySelectorAll('.watermark-item');
        if (watermarkList.length === 0) {
            // 水印被删除,重新生成
            createDOMWatermark('测试水印', targetSelector);
        }
    });
    // 开始监听目标容器的子节点变化
    observer.observe(targetDom, {
        childList: true,
        subtree: true
    });
}

// 修改createDOMWatermark方法,给每个水印元素添加className
function createDOMWatermark(watermarkText, targetSelector = 'body') {
    const targetDom = document.querySelector(targetSelector);
    if (!targetDom) return;
    const containerWidth = targetDom.offsetWidth;
    const containerHeight = targetDom.offsetHeight;
    const watermarkWidth = 200;
    const watermarkHeight = 150;
    const rowCount = Math.ceil(containerHeight / watermarkHeight);
    const colCount = Math.ceil(containerWidth / watermarkWidth);
    for (let i = 0; i < rowCount; i++) {
        for (let j = 0; j < colCount; j++) {
            const watermarkItem = document.createElement('div');
            watermarkItem.className = 'watermark-item';
            watermarkItem.style.position = 'absolute';
            watermarkItem.style.left = j * watermarkWidth + 'px';
            watermarkItem.style.top = i * watermarkHeight + 'px';
            watermarkItem.style.width = watermarkWidth + 'px';
            watermarkItem.style.height = watermarkHeight + 'px';
            watermarkItem.style.fontSize = '16px';
            watermarkItem.style.fontFamily = 'Microsoft YaHei';
            watermarkItem.style.color = 'rgba(0, 0, 0, 0.1)';
            watermarkItem.style.transform = 'rotate(-20deg)';
            watermarkItem.style.pointerEvents = 'none';
            watermarkItem.style.userSelect = 'none';
            watermarkItem.innerHTML = watermarkText;
            targetDom.appendChild(watermarkItem);
        }
    }
    // 添加防篡改监听
    addWatermarkProtect(targetSelector);
}

// 调用方法
createDOMWatermark('测试水印');

两种方案的对比选择

对比维度canvas水印方案DOM水印方案
性能只生成一张背景图,性能更好需要创建多个DOM元素,数量多时性能略差
灵活性水印内容修改需要重新生成canvas可以直接修改DOM元素内容,更灵活
防篡改难度修改背景图需要重新生成,防篡改相对容易DOM元素容易被单独删除,需要额外监听逻辑
适用场景全页面静态水印,不需要频繁修改水印内容水印内容需要动态调整,或者需要单个水印响应交互

开发者可以根据项目的实际需求选择合适的js水印实现方案,两种方案的核心逻辑都不复杂,只需要根据场景调整细节即可满足大部分水印使用需求。

js水印效果canvasDOM操作水印防篡改修改时间:2026-06-27 14:12:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。