前言

为了防止信息泄露或知识产权被侵犯,在web的世界里,对于图片文档等增加水印处理是十分有必要的。水印的添加根据环境可以分为两大类,前端浏览器环境添加和后端服务环境添加。

今天介绍的就是通过canvas创建一张含有水印信息的背景图片,通过vue指令插入到页面中。

配置

在vue项目中创建waterMark.ts文件

对外接口

  • 清除水印(clear)
  • 设置水印(setWatermark)
  • 初始化加载水印(loadingWatermark)

核心功能函数

  • 绘制文字背景图(createBase64)
  • 绘制水印层(createWatermark)
  • 页面随窗口大小调整更新(updateWatermark)
  • 初始化加载水印(loadingWatermark)
export function useWatermark(appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>
) {// 绘制文字背景图function createBase64() {}// 绘制水印层const createWatermark = () => {};// 页面随窗口调整更新水印function updateWatermark(){}// 对外提供的设置水印方法function setWatermark() {}// 清除水印const clear = () => {};//初始化加载水印const loadingWatermark() {}//方便传参预定义一个类型,可自行再扩展type attr = {font?: string;      //字体fontSize?: string;  //字体大小fillStyle?: string; //水印颜色width?:Number;      //宽度height?:Number;     //高度fillText?:string;   //水印文本};return { setWatermark, clear, loadingWatermark };
}

基本代码框架如上,也可自行添加

绘制文字背景图

function createBase64(item?: attr) {const can = document.createElement("canvas");const width = item?.width ?? 300;const height = item?.height ?? 240;const font = attr?.fontSize ?? "12px"+" "+attr?.font ?? "Reggae One";Object.assign(can, { width, height });const cans = can.getContext("2d");if (cans) {cans.rotate((-20 * Math.PI) / 120);cans.font = font;cans.fillStyle = attr?.fillStyle ?? "rgba(0, 0, 0, 0.12)";cans.textAlign = attr?.textAlign ?? "left";cans.textBaseline =attr?.textBaseline ?? "middle";cans.fillText(attr?.fillText, width / 20, height);}return can.toDataURL("image/png");}

绘制水印层

这个函数的主要逻辑是先判断如果已经绘制了水印层,直接调用更新水印方法,如果还没有,先动态创建一个 DIV 层,设置绝对定位,铺满当前整个浏览器窗口。

const id = domSymbol.toString();
const watermarkEl = shallowRef<HTMLElement>();const createWatermark = (item?: attr) => {if (unref(watermarkEl)) {updateWatermark({ str, attr });return id;}const div = document.createElement("div");watermarkEl.value = div;div.id = id;div.style.pointerEvents = "none";div.style.top = "0px";div.style.left = "0px";div.style.position = "absolute";div.style.zIndex = "100000";const el = unref(appendEl);if (!el) return id;const { clientHeight: height, clientWidth: width } = el;updateWatermark({ item.fillText, width, height, attr });el.appendChild(div);return id;};

更新水印

因为更新水印方法主要是根据当前窗口高度和宽度来的更新水印背景的设置,利用一张 Base64 格式的图片平铺即可。

function updateWatermark(options: {width?: number;height?: number;item?: attr;} = {}) {const el = unref(watermarkEl);if (!el) return;if (options.width !== "undefined") {el.style.width = `${options.width}px`;}if (ioptions.height !== "undefined") {el.style.height = `${options.height}px`;}if (options.item?.fillText!== "undefined") {el.style.background = `url(${createBase64(options.item)}) left top repeat`;}}

到此,我们实现了主要的三个功能函数,下面就是两个对外接口:

设置水印

这里的主要点是考虑设置页面resize监听,来及时更新水印的位置。还要考虑 Vue 的生命周期,当我们卸载页面的时候要进行清除水印。

function setWatermark(attr?: attr) {createWatermark(attr);addResizeListener(document.documentElement, func);const instance = getCurrentInstance();if (instance) {onBeforeUnmount(() => {clear();});}}const func = throttle(function () {const el = unref(appendEl);if (!el) return;const { clientHeight: height, clientWidth: width } = el;updateWatermark({ height, width });});

清除水印

清除水印的时候顺便移除窗口大小监听函数

  const clear = () => {const domId = unref(watermarkEl);watermarkEl.value = undefined;const el = unref(appendEl);if (!el) return;domId && el.removeChild(domId);removeResizeListener(el, func);};//在添加水印后切换页面可能会导致 domId为undefined,这边还提供另外一种清除水印的方法const clear1 = () => {const domId=document.getElementById(id);watermarkEl.value = undefined;const el = unref(appendEl);if (!el) return;domId && el.removeChild(domId);removeResizeListener(el, func);};const clear2 = () => {if (document.getElementById(id) !== null) {document.body.removeChild(document.getElementById(id));}};

全局使用或者指定页面

通过在设置水印的参数的时候预留的路由数组来判断,此方法可预留可不预留。下面提供了两种方式

//怎么保存设置看个人,只要方便操作就可以
//watermarkPagesInvolved是我存储路由的数组,dicMenu是调用方法的时候传进来的当前页面路由function LoadingsetWatermark(item?: attr, dicMenu?: string) {if (res.watermarkPagesInvolved.indexOf(dicMenu) != -1) {createWatermark(res as any);} else {clear();}}

水印功能的使用

import { useWatermark } from "/@/hooks/watermark";
import { defineComponent } from 'vue';
export default defineComponent({components: {useWatermark,},data() {return{/**水印设置 */formWater: {//文本filterText: '',//颜色color: '',//字体font: 'Vedana',//字体大小fontSize: 15,//垂直对齐textBaseline: 'middle',//水平对齐textAlign: 'left',//宽width: 300,//高height: 240,}}},
})onMounted(() => {const { setWatermark, clear } = useWatermark();nextTick(() => {setWatermark(formWater);});
});onBeforeUnmount(() => {clear();
});

指定页面使用

方式1,使用预留的方法

  • 1,在设置水印的时候预留一个数组来存储想要展示页面的路由
  • 2,在App.vue或者mian.ts中监听路由的变化,我这边使用的是在App.vue监听
  import { useWatermark } from './hooks/web/useWatermark';import { useRouter } from 'vue-router';const { LoadingsetWatermark } = useWatermark();const $router = useRouter();watch(() => $router.currentRoute.value.name,(newValue, oldValue) => {console.log(!newValue ? oldValue.toString() : newValue.toString());LoadingsetWatermark(!newValue ? oldValue.toString() : newValue.toString());},);

方式二,不使用预留的方法

  • 直接在App.vue或者main.ts判断是否创建水印

    watch:{$route:{handler (val, oldval) {let paths = ['/login', '/404', '/403', '/500']this.$nextTick(() => {if (paths.includes(val.path)) { //如果是以上url 则 不需要水印let my = document.getElementById("frame")my && my.parentNode.removeChild(my)} else if ((!paths.includes(val.path) && paths.includes(oldval.path)) || (!paths.includes(val.path) && oldval.path === '/')) {this.$nextTick(() => {this.watermark()})} else if (!(paths.includes(val.path) && paths.includes(oldval.path)) && !document.getElementById("frame")) {this.$nextTick(() => {this.watermark()})}})},// 深度观察监听// deep: true}},watermark() {// 认设置let info = getStore({name: 'userInfo'})if (isNull(info)) {return}let defaultSettings = {watermarl_element: "avue-view", // 要绘制元素的容器idwatermark_txt: `${info.userName}-<br/>`,watermark_img: '',watermark_x: 20, // 水印起始位置x轴坐标watermark_y: 50, // 水印起始位置Y轴坐标watermark_rows: 5, // 水印行数watermark_cols: 3, // 水印列数watermark_x_space: 100, // 水印x轴间隔watermark_y_space: 50, // 水印y轴间隔watermark_color: '#3e7ff7', // 水印字体颜色watermark_alpha: 0.2, // 水印透明度watermark_fontsize: '20px', // 水印字体大小watermark_font: '微软雅黑', // 水印字体watermark_width: 350, // 水印宽度watermark_height: 120, // 水印长度watermark_angle: 15 // 水印倾斜度数}let oTemp = document.createDocumentFragment();let maskElement = document.getElementsByClassName(defaultSettings.watermarl_element)[1] || document.body;//获取页面最大宽度let page_width = Math.min(maskElement.scrollWidth, maskElement.clientWidth);//获取页面最大高度let page_height = Math.min(maskElement.scrollHeight, maskElement.clientHeight);//水印数量自适应元素区域尺寸defaultSettings.watermark_cols = Math.ceil(page_width / (defaultSettings.watermark_x_space + defaultSettings.watermark_width));defaultSettings.watermark_rows = Math.ceil(page_height / (defaultSettings.watermark_y_space + defaultSettings.watermark_height));let xlet ylet frame = document.createElement('div')frame.setAttribute('id', 'frame')oTemp.appendChild(frame)for (var i = 0; i < defaultSettings.watermark_rows; i++) {y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * ifor (var j = 0; j < defaultSettings.watermark_cols; j++) {x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * jlet mask_div = document.createElement('div')mask_div.id = 'mask_div' + i + jmask_div.className = 'mask_div';// mask_img.className = 'mask_img';                                  //mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));mask_div.innerHTML = (defaultSettings.watermark_txt);// mask_img.src = defaultSettings.watermark_img;// mask_img.style.width = "150px";// mask_img.style.height = "50px";// 空白图片会有占位,判断src为空时移除img标签  不为空时添加img// if(defaultSettings.watermark_img == ""){//     mask_div.remove(mask_img);// }else{//   mask_div.append(mask_img);// }//设置水印div倾斜显示mask_div.style.transform = "rotate(-" + defaultSettings.watermark_angle + "deg)"mask_div.style.visibility = ""mask_div.style.position = "absolute"mask_div.style.left = x + 'px'mask_div.style.top = y + 'px'mask_div.style.overflow = "hidden"mask_div.style.zIndex = "9999"mask_div.style.pointerEvents = 'none'//pointer-events:none  让水印不遮挡页面的点击事件//mask_div.style.border="solid #eee 1px"//兼容IE9以下的透明度设置// mask_div.style.filter="alpha(opacity=50)";mask_div.style.opacity = defaultSettings.watermark_alphamask_div.style.fontSize = defaultSettings.watermark_fontsizemask_div.style.fontFamily = defaultSettings.watermark_fontmask_div.style.color = defaultSettings.watermark_colormask_div.style.textAlign = "center"mask_div.style.width = defaultSettings.watermark_width + 'px'mask_div.style.height = defaultSettings.watermark_height + 'px'mask_div.style.display = "block"frame.appendChild(mask_div)}}maskElement.appendChild(oTemp)
    }

前端页面添加全局水印或指定页面添加水印相关推荐

  1. 计算机页面添加文字水印在哪,怎么添加水印-Word小技巧-快速添加高大上的水印...

    不知道各位小伙伴是否见过这样的文档,带有类似[内部文件]/[严禁外泄]水印的文档,是不是觉得很高大上,神圣而不可侵犯的感觉油然而生?只需要一分钟,小编教你如何为文档快速添加水印. 一.添加水印 切换到 ...

  2. 前端给页面添加暗水印的办法

    前端给页面添加暗水印的办法 上一篇文章讲到了在页面上添加明水印的方法,但是明水印比较好清除,而且对于一些没做处理的图片,当用户直接保存的时候,是没有水印的,这时候信息泄露问题依然存在.为了解决这样的问 ...

  3. html页面中使用 JS 返回上一页及返回上一页并刷新,iframe中打开指定页面,跳转到指定页面

    html页面中使用 JS 返回上一页及返回上一页并刷新,iframe中打开指定页面,跳转到指定页面. 常用方法: window.history.go(-1); //返回上一页 window.histo ...

  4. c# 添加图片水印,可以指定水印位置+生成缩略图

    c# 添加图片水印,可以指定水印位置+生成缩略图 图片上传函数,进行判断是否加水印,做出两种处理方式: /**//// <summary> /// 上传图片代码 /// </summ ...

  5. vue项目 添加全局水印或某个指定页面水印 源码

    vue项目的页面添加水印,效果如图 index.vue import watermark from "./watermark"; mounted() {watermark.set( ...

  6. 使用JS(watermark)给HTML页面添加文字水印(全网最简单,最详细,复制即用,提供源码链接)

    前言: 最近在做项目,PD提需求让做一个页面水印,百度到的答案好像大部分都是图片的,要么七七八八的,百度了好久,现在总结出来了这个精简中的精简版的教程,与大家分享.(源码下载链接在文章末尾,如果不想看 ...

  7. js利用tab键切换当前页面_JavaScript跳转到指定页面并且到指定的tab切换窗口

    JavaScript跳转到指定页面并且到指定的tab切换窗口 案例的解析就是点击A页面的第一个的切换窗口的按钮跳转到B页面,再点击B页面的按钮跳转到A页面的第二个窗口,这个实现的效果有三种方法,下面的 ...

  8. js微信小程序页面左上角返回跳转指定页面

    微信小程序非导航栏tabBar页面左上角返回默认返回上一次的页面(即进入当前页面的前一页面),如果需要自定义页面,可以通过js中onUnload函数进行指定页面跳转. ①关闭所有页,打开url指定页面 ...

  9. 如何给web页面添加一个水印

    微信搜一搜 "胖蔡话前端" 前端公众号,关注更多前端咨询.欢迎访问个人博客[EnjoyToday.cn)(http://www.enjoytoday.cn) 水印原理 我们经常看到 ...

最新文章

  1. nginx 访问日志分析工具 goacess
  2. [转]Servlet3.1规范
  3. 多视图几何总结——基础矩阵、本质矩阵和单应矩阵的自由度分析
  4. MaskedTextBox
  5. UE4学习-虚幻4帮助手册、通过蓝图实现动画效果、添加时间轴、添加声音、C++和蓝图事件关联
  6. 电脑知识:电脑如何连接电视,在电视上显示?
  7. 货物配送问题的matlab,免疫算法求解配送中心选址问题matlab代码
  8. Idea启动报错 Error:java: System Java Compiler was not found in classpath
  9. 无维护地稳定运行了8 年的 Hyperic HQ
  10. html游戏贪吃蛇代码,html5贪吃蛇游戏使用63行代码完美实现
  11. datetime 索引_超全的数据库建表/SQL/索引规范,适合贴在工位上!
  12. 二叉链表java_二叉树的二叉链表存储(java实现)
  13. 利用键盘钩子捕捉linux键盘动作,利用键盘钩子捕获Windows键盘动作
  14. houdini安装哪个linux版本,Houdini18.5安装系统环境要求
  15. C#开发多语言翻译软件
  16. u盘引导linux加载raid卡驱动,解决方案:如何使用centos U盘加载Raid卡驱动程序_计算机基础知识_IT /计算机_资源...
  17. 平面几何----三割线定理引理的证明
  18. Java Web基础
  19. LeetCode #739 - Daily Temperatures
  20. http请求属性 Accept enctype Content-Type

热门文章

  1. 在windows或linux中使用VIM/VI复制粘贴内容命令及设置大全
  2. BIM设计师斑马:方案为主的建筑师,对于BIM的学习应该是一种怎样的流程呢?_BIM设计师斑马_新浪博客
  3. oracle连接出现问题
  4. Jmeter并发测试入门(非登录)
  5. 利用UART串口实现数据的收发
  6. 牛腩新闻发布--三元式
  7. 合并分区怎么操作?图文详解
  8. 特征分解(Eigendecomposition)
  9. 美篇发布《前浪》,解决社会对中老年误解问题
  10. MATLAB | 全网唯一 MATLAB双向弦图(有向弦图)绘制