返回顶部
首页 > 资讯 > 精选 >如何用Vue3指令实现水印背景
  • 579
分享到

如何用Vue3指令实现水印背景

2023-07-06 11:07:27 579人浏览 安东尼
摘要

这篇文章主要介绍了如何用vue3指令实现水印背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用Vue3指令实现水印背景文章都会有所收获,下面我们一起来看看吧。首先定义一个指令,我们要明确两点:命名(v-w

这篇文章主要介绍了如何用vue3指令实现水印背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用Vue3指令实现水印背景文章都会有所收获,下面我们一起来看看吧。

首先定义一个指令,我们要明确两点:命名(v-water-mask)和绑定值(配置值,option),实现如下:

<div v-water-mask:options="wmOption"></div>// 配置值const wmOption = Reactive<WMOptions>({  textArr: ['路灯下的光', `${dayjs().fORMat('YYYY-MM-DD HH:mm')}`],  deg: -35,});

效果如下图所示:

如何用Vue3指令实现水印背景

从上图中我们可以看出,文字有文本以及时间字符串,水印文字都是倾斜了一定角度,其实就是旋转了一定角度的。那么问题来了,我们可能问这些是怎么设置的?首先这需要使用指令的时候通过一些配置来实现一些固定值,下面这里都把这些配置都封装成一个类了,为什么要这样做?这样就不用使用的时候每次都要设定一个默认值,比如通过定义接口来引用这些配置时每次都需要设置一个默认值:

export class WMOptions {  constructor(init?: WMOptions) {    if (init) {      Object.assign(this, init);    }  }  textArr: Array<string> = ['test', '自定义水印']; // 需要展示的文字,多行就多个元素【必填】  font?: string = '16px "微软雅黑"'; // 字体样式  fillStyle?: string = 'rgba(170,170,170,0.4)'; // 描边样式  maxWidth?: number = 200; // 文字水平时最大宽度  minWidth?: number = 120; // 文字水平时最小宽度  lineHeight?: number = 24; // 文字行高  deg?: number = -45; // 旋转的角度 0至-90之间  marginRight?: number = 120; // 每个水印的右间隔  marginBottom?: number = 40; // 每个水印的下间隔  left?: number = 20; // 整体背景距左边的距离  top?: number = 20; // 整体背景距上边的距离  opacity?: string = '.75'; // 文字透明度  position?: 'fixed' | 'absolute' = 'fixed'; // 容器定位方式(值为absolute时,需要指定一个父元素非static定位)}

细心的地我们可能会发现显示地文本是一个数组,这样主要是为了方便分行,聪明地我们可能会问:假如其中一个比较长怎么换行?,别急别急,我们先了解一下指令是怎么定义的:

定义指令:首先定义为一个ObjectDirective对象类型,因为指令也就是通过在不同生命周期中对当前元素做一些操作。

const WaterMask: ObjectDirective = {  // el为当前元素  // bind是当前绑定的属性,注意地,由于是vue3实现,这个值是一个ref类型    beforeMount(el: htmlElement, binding: DirectiveBinding) {        // 实现水印的核心方法        waterMask(el, binding);    },    mounted(el: HTMLElement, binding: DirectiveBinding) {        nextTick(() => {          // 禁止修改水印          disablePatchWaterMask(el);        });    },    beforeUnmount() {        // 清除监听DOM节点的监听器        if (observerTemp.value) {          observerTemp.value.disconnect();          observerTemp.value = null;        }    },};export default WaterMask;
  • waterMask方法:实现水印业务细节呈现,对文字的自适应换行,根据页面元素大小来计算合适宽高值。

  • disablePatchWaterMask方法:通过MutationObserver方法监听DOM元素修改,从而阻止用户取消水印的呈现。

声明指令:在main文件中定义声明指令,这样我们就可以全局使用这个指令了

app.directive('water-mask', WaterMask);

接下来我们来看一一分析水印的两个核心方法:waterMask和disablePatchWaterMask。

实现水印功能

通过waterMask方法实现,waterMask方法主要是做了四件事情:

let defaultSettings = new WMOptions();const waterMask = function (element: HTMLElement, binding: DirectiveBinding) {  // 合并默认值和传参配置  defaultSettings = Object.assign({}, defaultSettings, binding.value || {});  defaultSettings.minWidth = Math.min(    defaultSettings.maxWidth!,    defaultSettings.minWidth!  ); // 重置最小宽度  const textArr = defaultSettings.textArr;  if (!Util.isArray(textArr)) {    throw Error('水印文本必须放在数组中!');  }  const c = createcanvas(); // 动态创建隐藏的canvas  draw(c, defaultSettings); // 绘制文本  convertCanvasToImage(c, element); // 转化图像};

获取配置的默认值:由于开发者传参的时候不一定需要把所有配置的传进来,其实按照本身默认的一些值就行,通过浅拷贝把指令绑定的值传进来的一起融合一起就可以更新默认的配置:

创建canvas标签:因为是通过canvas实现的,我们本身是没有直接在template中呈现这个标签,所以需要通过document对象创建canvas标签:

function createCanvas() {  const c = document.createElement('canvas');  c.style.display = 'none';  document.body.appendChild(c);  return c;}

绘制文本:首先遍历传入需要显示的水印信息,也就是textArr文本数组,遍历数组判断数组元素是不是超出了配置的每个水印默认宽高,然后根据文本元素返回超出文本长度的文本分割数组,同时把文本最大宽度返回,最后通过切割结果动态修改canvas的宽高。

function draw(c: any, settings: WMOptions) {  const ctx = c.getContext('2d');  // 切割超过最大宽度的文本并获取最大宽度  const textArr = settings.textArr || []; // 水印文本数组  let WordBreakTextArr: Array<any> = [];  const maxWidthArr: Array<number> = [];  // 遍历水印文本数组,判断每个元素的长度  textArr.forEach((text) => {    const result = breakLinesForCanvas(ctx,text + '',settings.maxWidth!,settings.font!);    // 合并超出最大宽度的分割数组    wordBreakTextArr = wordBreakTextArr.concat(result.textArr);    // 最大宽度    maxWidthArr.push(result.maxWidth);  });  // 最大宽度排序,最后取最大的最大宽度maxWidthArr[0]  maxWidthArr.sort((a, b) => {    return b - a;  });  // 根据需要切割结果,动态改变canvas的宽和高  const maxWidth = Math.max(maxWidthArr[0], defaultSettings.minWidth!);  const lineHeight = settings.lineHeight!;  const height = wordBreakTextArr.length * lineHeight;  const degToPI = (Math.PI * settings.deg!) / 180;  const absDeg = Math.abs(degToPI);  // 根据旋转后的矩形计算最小画布的宽高  const hSinDeg = height * Math.sin(absDeg);  const hCosDeg = height * Math.cos(absDeg);  const wSinDeg = maxWidth * Math.sin(absDeg);  const wCosDeg = maxWidth * Math.cos(absDeg);  c.width = parseInt(hSinDeg + wCosDeg + settings.marginRight! + '', 10);  c.height = parseInt(wSinDeg + hCosDeg + settings.marginBottom! + '', 10);  // 宽高重置后,样式也需重置  ctx.font = settings.font;  ctx.fillStyle = settings.fillStyle;  ctx.textBaseline = 'hanging'; // 默认是alphabetic,需改基准线为贴着线的方式  // 移动并旋转画布  ctx.translate(0, wSinDeg);  ctx.rotate(degToPI);  // 绘制文本  wordBreakTextArr.forEach((text, index) => {    ctx.fillText(text, 0, lineHeight * index);  });}

从上面代码中我们可以看出绘制文本的核心操作是切割超长文本和动态修改canvas的宽高。我们接下来看看这两个操作是如何实现的?

measureText()方法是基于当前字型来计算字符串宽度的。

// 根据最大宽度切割文字function breakLinesForCanvas(context: any,text: string,width: number,font: string) {  const result = [];  let maxWidth = 0;  if (font) {    context.font = font;  }  // 查找切割点  let breakPoint = findBreakPoint(text, width, context);  while (breakPoint !== -1) {    // 切割点前的元素入栈    result.push(text.substring(0, breakPoint));    // 切割点后的元素    text = text.substring(breakPoint);    maxWidth = width;    // 查找切割点后的元素是否还有切割点    breakPoint = findBreakPoint(text, width, context);  }  // 如果切割的最后文本还有文本就push  if (text) {    result.push(text);    const lastTextWidth = context.measureText(text).width;    maxWidth = maxWidth !== 0 ? maxWidth : lastTextWidth;  }  return {    textArr: result,    maxWidth: maxWidth,  };}
// 寻找切换断点function findBreakPoint(text: string, width: number, context: any) {  let min = 0;  let max = text.length - 1;  while (min <= max) {    // 二分字符串中点    const middle = Math.floor((min + max) / 2);    // measureText()方法是基于当前字型来计算字符串宽度的    const middleWidth = context.measureText(text.substring(0, middle)).width;    const oneCharWiderThanMiddleWidth = context.measureText(      text.substring(0, middle + 1)    ).width;    // 判断当前文本切割是否超了的临界点    if (middleWidth <= width && oneCharWiderThanMiddleWidth > width) {      return middle;    }    // 如果没超继续遍历查找    if (middleWidth < width) {      min = middle + 1;    } else {      max = middle - 1;    }  }  return -1;}

如何用Vue3指令实现水印背景

所以canvas图形宽为hSinDeg + wCosDeg + settings.marginRight。canvas图形高为:wSinDeg + hCosDeg + settings.marginBottom。

  • 切割超长文本:

  • 寻找切割点:通过二分查找方法查询字符串超长的位置在哪里:

  • 动态修改canvas的宽高:通过旋转的角度值、最大宽度值以及勾股定理一一计算宽度和高度,首先我们需要把旋转的角度转换为弧度值(公式:&pi;/180&times;角度,也就是 (Math.PI*settings.deg!) / 180 ),我们先看看下图:

转化图像:通过对当前canvas配置转化为图形url,然后配置元素的style属性。

// 将绘制好的canvas转成图片function convertCanvasToImage(canvas: any, el: HTMLElement) {  // 判断是否为空渲染器  if (Util.isUndefinedOrNull(el)) {    console.error('请绑定渲染容器');  } else {    // 转化为图形数据的url    const imgData = canvas.toDataURL('image/png');    const divMask = el;    divMask.style.CSSText = `position: ${defaultSettings.position}; left:0; top:0; right:0; bottom:0; z-index:9999; pointer-events:none;opacity:${defaultSettings.opacity}`;    divMask.style.backgroundImage = 'url(' + imgData + ')';    divMask.style.backgroundPosition =      defaultSettings.left + 'px ' + defaultSettings.top + 'px';  }}

实现禁止用户修改水印

我们都知道,如果用户需要修改html一般都会浏览器调式中的Elements中修改我们网页的元素的样式就可以,也就是我们只要监听到DOM元素被修改就可以,控制修改DOM无法生效。

由于修改DOM有两种方法:修改元素节点和修改元素属性,所以只要控制元素的相关DOM方法中进行相应操作就可以实现我们的禁止。而通过disablePatchWaterMask方法主要做了三件事情:

  • 创建MutationObserver实例:也就是实例化MutationObserver,这样才能调用MutationObserver中的observe函数实现DOM修改的监听。

  • 创建MutationObserver回调函数:通过传入的两个参数,一个当前元素集合和observer监听器。

  • 监听需要监听的元素:调用observer需要传入监听元素以及监听配置,这个可以参考一下MutationObserver用法配置。

function disablePatchWaterMask(el: HTMLElement) {  // 观察器的配置(需要观察什么变动)  const config = {    attributes: true,    childList: true,    subtree: true,    attributeOldValue: true,  };    const MutationObserver =    window.MutationObserver || window.WEBKitMutationObserver;  // 当观察到变动时执行的回调函数  const callback = function (mutationsList: any, observer: any) {    console.log(mutationsList);    for (let mutation of mutationsList) {      let type = mutation.type;      switch (type) {        case 'childList':          if (mutation.removednodes.length > 0) {            // 删除节点,直接从删除的节点数组中添加回来            mutation.target.append(mutation.removedNodes[0]);          }          break;        case 'attributes':          // 为什么是这样处理,我们看一下下面两幅图          mutation.target.setAttribute('style', mutation.target.oldValue);          break;        default:          break;      }    }  };  // 创建一个观察器实例并传入回调函数  const observer = new MutationObserver(callback);  // 以上述配置开始观察目标节点  observer.observe(el, config);  observerTemp.value = observer;}

如何用Vue3指令实现水印背景

从水印到取消水印(勾选到不勾选background-image):我们发现mutation.target属性中的oldValue值就是我们设置style。

如何用Vue3指令实现水印背景

从取消水印到恢复水印(不勾选到勾选background-image):我们发现mutation.target属性中的oldValue值的background-image被注释掉了。

从上面两个转化中,我们就可以直接得出直接赋值当勾选到不勾选是监听到DOM修改的oldValue(真正的style),因为这时候获取到的才是真正style,反之就不是了,由于我们不勾选时的oldValue赋值给不勾选时的style,所以当我们不勾选时再转化为勾选时就是真正style,从而实现不管用户怎么操作都不能取消水印。

关于“如何用Vue3指令实现水印背景”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“如何用Vue3指令实现水印背景”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

--结束END--

本文标题: 如何用Vue3指令实现水印背景

本文链接: https://lsjlt.com/news/357969.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何用Vue3指令实现水印背景
    这篇文章主要介绍了如何用Vue3指令实现水印背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用Vue3指令实现水印背景文章都会有所收获,下面我们一起来看看吧。首先定义一个指令,我们要明确两点:命名(v-w...
    99+
    2023-07-06
  • 怎么用Vue3指令实现水印背景
    页面水印业务相信我们都有遇过,为什么需要给页面添加水印?为了保护自己的版权和知识产权,给图片加上水印一般是为了防止盗图者用于商业用途,损害原作者的权益。那么在我们开发当中有什么方法可以实现呢?一般分为前端实现和后端实现这两种方法,本文主要是...
    99+
    2023-05-14
    Vue3
  • Vue3 实现网页背景水印功能的示例代码
    经常有一些公司和组织出于系统文件或信息安全保密的需要,需要在系统网页上增加带有个人标识(系统账号或个人信息)的水印,可以简单防止截图外传 首先我们来看这样一个水印功能的实现思路,通...
    99+
    2022-11-13
    vue网页水印 vue网页背景水印
  • ps如何去掉水印不伤背景
    这篇文章主要介绍ps如何去掉水印不伤背景,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!方法如下打开水印的素材,确认想要去除的文字,Ctrl+J复制图层,此时得到图层1,然后打开魔棒工具,把水印载入选区。返回工具栏,点...
    99+
    2023-06-15
  • 如何使用js给网页加上水印背景
    这篇文章将为大家详细讲解有关如何使用js给网页加上水印背景,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。水印方法export function wat...
    99+
    2024-04-02
  • Java实现全图背景水印的示例详解
    目录给图片添加水印的优点给图片添加水印的缺点添加全图水印给图片添加水印的优点 可以保护图片的版权:给图片添加水印可以显著地提高图片的版权保护效果。通常,如果没有版权水印的图片在网络上...
    99+
    2023-02-10
    Java实现全图背景水印 Java全图背景水印 Java 水印
  • 如何使用CSS3伪元素构建文章水印背景
    这篇文章主要为大家展示了“如何使用CSS3伪元素构建文章水印背景”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用CSS3伪元素构建文章水印背景”这篇文章吧...
    99+
    2024-04-02
  • VB.NET如何实现水印
    这篇文章主要介绍了VB.NET如何实现水印,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。水印技术VB.NET水印类(watermark)包含很多属性,可用于测定在原图像的哪个...
    99+
    2023-06-17
  • Vue使用自定义指令实现页面底部加水印
    项目场景 给项目的整个背景加上自定义水印,可以改变水印的文案和字体颜色等 实现思路 这里使用的技术主要是canvas,在实现水印的过程中,主要使用了canvas的特性 ...
    99+
    2024-04-02
  • Vue全局水印如何实现
    今天小编给大家分享一下Vue全局水印如何实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。...
    99+
    2024-04-02
  • 前端canvas如何实现水印
    小编给大家分享一下前端canvas如何实现水印,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!两种水印效果如图:原理解析:图一斜纹类:创建一个和页面一样大的画布,根...
    99+
    2023-06-09
  • css中背景background如何实现图片水平垂直居中
    这篇文章将为大家详细讲解有关css中背景background如何实现图片水平垂直居中,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。背景background实现图片水平垂直...
    99+
    2024-04-02
  • web开发中如何实现水印
    这篇文章主要为大家展示了“web开发中如何实现水印”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“web开发中如何实现水印”这篇文章吧。分析问题首先,考虑到业务场...
    99+
    2024-04-02
  • CSS如何实现背景效果
    这篇文章主要介绍了CSS如何实现背景效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。数量级对背景图形的影响本文的主角主要是:多重径向渐变(repeating-radial-...
    99+
    2023-06-14
  • css3如何实现背景模糊
    这篇文章主要介绍了css3如何实现背景模糊,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、普通背景模糊代码:<Style>   &...
    99+
    2023-06-08
  • css如何实现全屏背景
    这篇文章主要为大家展示了“css如何实现全屏背景”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“css如何实现全屏背景”这篇文章吧。CSS3:全屏背景html {  ...
    99+
    2023-06-19
  • CSS如何实现背景镂空
    这篇文章主要介绍“CSS如何实现背景镂空”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“CSS如何实现背景镂空”文章能帮助大家解决问题。背景镂空.header {    posit...
    99+
    2023-07-05
  • Android如何实现背景动画
    这篇文章主要介绍了Android如何实现背景动画,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体如下:先创建动画层,有三张图片<xml version=&q...
    99+
    2023-05-30
    android
  • vue3中使用VueParticles实现粒子动态背景效果
    目录particles.vue3官网可以仔细看下这里 有案例跟文档官网 Demo好了直接进入主题 安装使用Vue3 语法糖中使用配置单独写到文件particles.js,代码看起来简...
    99+
    2024-04-02
  • vue3中怎么使用particles插件实现粒子背景
    这篇文章主要介绍了vue3中怎么使用particles插件实现粒子背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue3中怎么使用particles插件实现粒子背景文章都会有所收获,下面我们一起来看看吧。效...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作