iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何用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://www.lsjlt.com/news/357969.html(转载时请注明来源链接)

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何用Vue3指令实现水印背景
    这篇文章主要介绍了如何用Vue3指令实现水印背景的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用Vue3指令实现水印背景文章都会有所收获,下面我们一起来看看吧。首先定义一个指令,我们要明确两点:命名(v-w...
    99+
    2023-07-06
  • 怎么用Vue3指令实现水印背景
    页面水印业务相信我们都有遇过,为什么需要给页面添加水印?为了保护自己的版权和知识产权,给图片加上水印一般是为了防止盗图者用于商业用途,损害原作者的权益。那么在我们开发当中有什么方法可以实现呢?一般分为前端实现和后端实现这两种方法,本文主要是...
    99+
    2023-05-14
    Vue3
  • Vue3 实现网页背景水印功能的示例代码
    经常有一些公司和组织出于系统文件或信息安全保密的需要,需要在系统网页上增加带有个人标识(系统账号或个人信息)的水印,可以简单防止截图外传 首先我们来看这样一个水印功能的实现思路,通...
    99+
    2022-11-13
    vue网页水印 vue网页背景水印
  • 如何使用js给网页加上水印背景
    这篇文章将为大家详细讲解有关如何使用js给网页加上水印背景,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。水印方法export function wat...
    99+
    2022-10-19
  • 如何使用CSS3伪元素构建文章水印背景
    这篇文章主要为大家展示了“如何使用CSS3伪元素构建文章水印背景”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用CSS3伪元素构建文章水印背景”这篇文章吧...
    99+
    2022-10-19
  • Vue使用自定义指令实现页面底部加水印
    项目场景 给项目的整个背景加上自定义水印,可以改变水印的文案和字体颜色等 实现思路 这里使用的技术主要是canvas,在实现水印的过程中,主要使用了canvas的特性 ...
    99+
    2022-11-12
  • css中背景background如何实现图片水平垂直居中
    这篇文章将为大家详细讲解有关css中背景background如何实现图片水平垂直居中,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。背景background实现图片水平垂直...
    99+
    2022-10-19
  • 如何在Vue3中实现自定义指令(超详细!)
    目录前言生命周期钩子的参数简化形式对象字面量在组件上使用指令几个实用的自定义指令自动聚焦v-focus防抖v-debounce节流v-throttle弹窗隐藏v-hide总结在开发V...
    99+
    2022-11-13
  • 详解如何用JS实现覆盖水印效果
    废话开篇:简单实现一个覆盖水印的小功能,水印一般都是添加在图片上,然后直接加载处理过的图片url即可,这里并没有修改图片,而是直接的在待添加水印的 dom 上添加一个 canvas 蒙版。一、效果处理之前DIVIMG处理之后DIVIMG这里...
    99+
    2023-05-14
    JavaScript 前端
  • 一篇文章告诉你Vue3指令是如何实现的
    目录前言指令注册全局注册组件内注册指令搜寻指令搜寻的时机指令搜寻的逻辑指令绑定VNode指令调用关于指令的思考组件上使用指令组件上的一些使用场景总结前言 Vue 指令 是指 对普通D...
    99+
    2022-11-13
  • linux shell中如何实现控制台打印各种颜色字体和背景
    这篇文章给大家分享的是有关linux shell中如何实现控制台打印各种颜色字体和背景的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 问题控制台打印各种颜色字体和背景字体颜色#30:黑 #31:红&n...
    99+
    2023-06-09
  • 如何使用canvas实现给图片添加平铺水印
    小编给大家分享一下如何使用canvas实现给图片添加平铺水印,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!最近项目中遇到一个需求,需要把一张图片加上平铺的水印类似...
    99+
    2023-06-09
  • 如何使用CSS来实现网页背景半透明
    小编给大家分享一下如何使用CSS来实现网页背景半透明,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! 一、DIV CSS半透明根...
    99+
    2022-10-19
  • 如何使用CSS实现响应式全屏背景图
    小编给大家分享一下如何使用CSS实现响应式全屏背景图,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!使用background-size 属性,填充整个viewport. 当css属...
    99+
    2022-10-19
  • OpenCV如何利用对比度亮度变换实现水印去除
    OpenCV如何利用对比度亮度变换实现水印去除,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。导读主要介绍使用OpenCV亮度/对比度变换来去除图片水印的实例。背景介绍Ope...
    99+
    2023-06-21
  • 如何使用CSS实现body背景层高于块元素
    这篇文章主要介绍了如何使用CSS实现body背景层高于块元素,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。代码如下:<!DOCTYPE...
    99+
    2022-10-19
  • JavaScript如何用按钮触发实现背景色的闪烁
    这篇文章主要介绍了JavaScript如何用按钮触发实现背景色的闪烁的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript如何用按钮触发实现背景色的闪烁文章都会有所...
    99+
    2022-10-19
  • 如何使用HTML和CSS实现一个全屏背景布局
    在网页设计中,全屏背景布局是一种常见且炫酷的效果,能够更好地展示网站内容,给用户带来良好的视觉体验。本文将介绍如何使用HTML和CSS实现一个全屏背景布局,并提供具体的代码示例。首先,在HTML文件中创建一个基本的布局结构。以下是一个简单的...
    99+
    2023-10-21
    HTML布局 CSS背景 全屏布局
  • 如何使用CSS cross-fade()实现背景图像半透明效果
    这篇文章主要介绍如何使用CSS cross-fade()实现背景图像半透明效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、需求描述某元素,希望 background-image 背景图片是半透明的,但是,元素里...
    99+
    2023-06-08
  • Android开发如何实现Launcher3应用列表修改透明背景
    小编给大家分享一下Android开发如何实现Launcher3应用列表修改透明背景,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体如下:Launcher时开机完成后第一个启动的应用,用来展示应用列表和快捷方式、小部件等。...
    99+
    2023-05-30
    android launcher3
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作