検索
ホームページウェブフロントエンドVue.jsVue3 命令を使用して透かしの背景を実装する方法

誰もがページの透かしビジネスに遭遇したことがあると思いますが、なぜページに透かしを追加する必要があるのでしょうか?自分の著作権と知的財産権を保護するために、画像に透かしを追加するのは一般に、海賊版が画像を商業目的で使用したり、元の作者の権利を侵害したりするのを防ぐためです。では、私たちの開発ではどのような方法が実現できるのでしょうか?フロントエンド実装とバックエンド実装の 2 つの方法に大別されますが、この記事では主にフロントエンド実装方法の学習に焦点を当てます:

  • 方法 1: フォントをブロックで直接囲む要素を作成し、絶対位置を動的に設定してから、transform 属性を使用して回転させます。ただし、考慮する必要がある問題があり、画像が大きすぎる場合や画像の数が多すぎる場合は、パフォーマンスに重大な影響を与えるため、この方法については詳しく説明しません。

  • 方法 2: キャンバス上にフォントを描画し、スタイルを設定し、最後にそれを画像としてエクスポートし、その画像を透かしレイヤーの背景画像として使用します。

ウォーターマーク レイヤーについて学ぶ前に、まず 2 つの質問をします。

  • ウォーターマーク テキストが長い場合、ウォーターマークは適応可能ですか?

  • ユーザーによるウォーターマークの変更と削除を制限できますか?

実際、上記の 2 つの質問は、ページの透かしを作成するときに考慮する必要がある 2 つの中心的な問題です。それでは、早速、質問を一緒に見ていきましょう??? 。

最初にコマンドを定義します。名前付け (v-water-mask) とバインド値 (設定値、オプション) の 2 点を明確にする必要があります。実装は次のとおりです:

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

The効果は次の図に示すとおりです。 表示:

Vue3 命令を使用して透かしの背景を実装する方法

上の図から、テキストにはテキストと時間の文字列が含まれており、透かしテキストは一定の角度で傾いていることがわかります。角度、実際には特定の角度で回転します。そこで疑問が生じます。これらはどのように設定されているのでしょうか?まず第一に、これには命令を使用するときにいくつかの固定値を達成するためにいくつかの設定が必要です。以下では、これらの設定はクラスにカプセル化されています。なぜこれを行うのでしょうか?この方法では、使用するたびにデフォルト値を設定する必要はありません。たとえば、インターフェイスを定義してこれらの構成を参照する場合、毎回デフォルト値を設定する必要があります:

export class WMOptions {
  constructor(init?: WMOptions) {
    if (init) {
      Object.assign(this, init);
    }
  }
  textArr: Array<string> = [&#39;test&#39;, &#39;自定义水印&#39;]; // 需要展示的文字,多行就多个元素【必填】
  font?: string = &#39;16px "微软雅黑"&#39;; // 字体样式
  fillStyle?: string = &#39;rgba(170,170,170,0.4)&#39;; // 描边样式
  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 = &#39;.75&#39;; // 文字透明度
  position?: &#39;fixed&#39; | &#39;absolute&#39; = &#39;fixed&#39;; // 容器定位方式(值为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 要素の変更を監視し、ユーザーがウォーターマークの表示をキャンセルできないようにします。

宣言命令: この命令をグローバルに使用できるように、メイン ファイルで宣言命令を定義します。

app.directive(&#39;water-mask&#39;, WaterMask);

次に、2 つのウォーターマークを 1 つずつ分析しましょう。 2 つのコア メソッド:waterMask と disablePatchWaterMask。

ウォーターマーク関数の実装

waterMask メソッドによって達成されます。waterMask メソッドは主に 4 つのことを行います:

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(&#39;水印文本必须放在数组中!&#39;);
  }
  const c = createCanvas(); // 动态创建隐藏的canvas
  draw(c, defaultSettings); // 绘制文本
  convertCanvasToImage(c, element); // 转化图像
};

設定のデフォルト値を取得します: 開発者がパラメーターを渡すとき必ずしもすべての設定を渡す必要はありません。実際には、デフォルト値の一部に従うだけです。指示によってバインドされた値を浅くコピーし、それらを融合することで、デフォルト設定を更新できます:

キャンバス タグの作成 : キャンバス タグはキャンバスを通じて実装されるため、このラベルはテンプレートに直接表示されません。したがって、ドキュメント オブジェクトを通じてキャンバス ラベルを作成する必要があります:

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

描画テキスト:まず、表示する必要がある透かし情報を走査します。これは textArr テキスト配列です。配列を走査して、配列要素が構成されている各透かしのデフォルトの幅と高さを超えているかどうかを判断します。次に、この配列を超えるテキスト セグメンテーション配列を返します。テキスト要素に基づいてテキストの長さを返します。同時にテキストの最大幅を返します。最後に、キャンバスはカット結果を通じて動的に変更されます。幅と高さです。

function draw(c: any, settings: WMOptions) {
  const ctx = c.getContext(&#39;2d&#39;);
  // 切割超过最大宽度的文本并获取最大宽度
  const textArr = settings.textArr || []; // 水印文本数组
  let wordBreakTextArr: Array<any> = [];
  const maxWidthArr: Array<number> = [];
  // 遍历水印文本数组,判断每个元素的长度
  textArr.forEach((text) => {
    const result = breakLinesForCanvas(ctx,text + &#39;&#39;,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! + &#39;&#39;, 10);
  c.height = parseInt(wSinDeg + hCosDeg + settings.marginBottom! + &#39;&#39;, 10);
  // 宽高重置后,样式也需重置
  ctx.font = settings.font;
  ctx.fillStyle = settings.fillStyle;
  ctx.textBaseline = &#39;hanging&#39;; // 默认是alphabetic,需改基准线为贴着线的方式
  // 移动并旋转画布
  ctx.translate(0, wSinDeg);
  ctx.rotate(degToPI);
  // 绘制文本
  wordBreakTextArr.forEach((text, index) => {
    ctx.fillText(text, 0, lineHeight * index);
  });
}

上記のコードから、テキスト描画の中心的な操作は、長すぎるテキストを切り取り、キャンバスの幅と高さを動的に変更することであることがわかります。これら 2 つの操作がどのように実装されるかを見てみましょう。

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 命令を使用して透かしの背景を実装する方法

したがって、キャンバスのグラフィック幅は hSinDeg wCosDeg settings.marginRight になります。キャンバス グラフィックの高さは、wSinDeg hCosDeg settings.marginBottom です。

  • 非常に長いテキストを切り取る:

  • 切り取りポイントを見つける: 二分検索メソッドを使用して、非常に長い文字列の位置をクエリします:

  • キャンバスの幅と高さを動的に変更する: 回転角度の値、最大幅の値、およびピタゴラスの定理を使用して、幅と高さを 1 つずつ計算します。回転角度をラジアン値に変換します (式: π/180×Angle、つまり (Math.PI*settings.deg!) / 180)、まず次の図を見てみましょう:

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

// 将绘制好的canvas转成图片
function convertCanvasToImage(canvas: any, el: HTMLElement) {
  // 判断是否为空渲染器
  if (Util.isUndefinedOrNull(el)) {
    console.error(&#39;请绑定渲染容器&#39;);
  } else {
    // 转化为图形数据的url
    const imgData = canvas.toDataURL(&#39;image/png&#39;);
    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 = &#39;url(&#39; + imgData + &#39;)&#39;;
    divMask.style.backgroundPosition =
      defaultSettings.left + &#39;px &#39; + defaultSettings.top + &#39;px&#39;;
  }
}

实现禁止用户修改水印

我们都知道,如果用户需要修改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,
  };
  /* MutationObserver 是一个可以监听DOM结构变化的接口。 */
  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 &#39;childList&#39;:
          if (mutation.removedNodes.length > 0) {
            // 删除节点,直接从删除的节点数组中添加回来
            mutation.target.append(mutation.removedNodes[0]);
          }
          break;
        case &#39;attributes&#39;:
          // 为什么是这样处理,我们看一下下面两幅图
          mutation.target.setAttribute(&#39;style&#39;, 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 命令を使用して透かしの背景を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は亿速云で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
Vue.js:Web開発におけるその役割を定義しますVue.js:Web開発におけるその役割を定義しますApr 18, 2025 am 12:07 AM

Web開発におけるVue.jsの役割は、開発プロセスを簡素化し、効率を向上させるプログレッシブJavaScriptフレームワークとして機能することです。 1)開発者は、レスポンシブデータのバインディングとコンポーネント開発を通じてビジネスロジックに集中できるようになります。 2)VUE.JSの作業原則は、パフォーマンスを最適化するためにレスポンシブシステムと仮想DOMに依存しています。 3)実際のプロジェクトでは、VUEXを使用してグローバルな状態を管理し、データの応答性を最適化することが一般的な慣行です。

Vue.jsの理解:主にフロントエンドフレームワークVue.jsの理解:主にフロントエンドフレームワークApr 17, 2025 am 12:20 AM

Vue.jsは、2014年にYou YuxiがリリースしたプログレッシブJavaScriptフレームワークで、ユーザーインターフェイスを構築します。その中心的な利点には、次のものが含まれます。1。レスポンシブデータバインディング、データ変更の自動更新ビュー。 2。コンポーネントの開発では、UIは独立した再利用可能なコンポーネントに分割できます。

Netflixのフロントエンド:React(またはVue)の例とアプリケーションNetflixのフロントエンド:React(またはVue)の例とアプリケーションApr 16, 2025 am 12:08 AM

Netflixは、Reactをフロントエンドフレームワークとして使用します。 1)Reactのコンポーネント開発モデルと強力なエコシステムが、Netflixがそれを選択した主な理由です。 2)コンポーネント化により、Netflixは複雑なインターフェイスをビデオプレーヤー、推奨リスト、ユーザーコメントなどの管理可能なチャンクに分割します。 3)Reactの仮想DOMおよびコンポーネントライフサイクルは、レンダリング効率とユーザーインタラクション管理を最適化します。

フロントエンドの風景:Netflixが選択にアプローチした方法フロントエンドの風景:Netflixが選択にアプローチした方法Apr 15, 2025 am 12:13 AM

Netflixのフロントエンドテクノロジーでの選択は、主にパフォーマンスの最適化、スケーラビリティ、ユーザーエクスペリエンスの3つの側面に焦点を当てています。 1。パフォーマンスの最適化:Netflixは、Reactをメインフレームワークとして選択し、SpeedCurveやBoomerangなどのツールを開発して、ユーザーエクスペリエンスを監視および最適化しました。 2。スケーラビリティ:マイクロフロントエンドアーキテクチャを採用し、アプリケーションを独立したモジュールに分割し、開発効率とシステムのスケーラビリティを改善します。 3.ユーザーエクスペリエンス:Netflixは、Material-UIコンポーネントライブラリを使用して、A/Bテストとユーザーフィードバックを介してインターフェイスを継続的に最適化して、一貫性と美学を確保します。

React vs. Vue:Netflixはどのフレームワークを使用していますか?React vs. Vue:Netflixはどのフレームワークを使用していますか?Apr 14, 2025 am 12:19 AM

netflixusesaCustomframeworkは、「ギボン」ビルトンリアクト、notreactorvuedirectly.1)チームエクスペリエンス:seice basedonfamperivity.2)projectomplerprojects:vueforsplerprojects、racefforcomplexones.3)customeforsneeds:reactofforsmorefloficailie.

フレームワークの選択:Netflixの決定を推進するものは何ですか?フレームワークの選択:Netflixの決定を推進するものは何ですか?Apr 13, 2025 am 12:05 AM

Netflixは、主に、パフォーマンス、スケーラビリティ、開発効率、エコシステム、技術的な負債、およびフレームワーク選択におけるメンテナンスコストを考慮しています。 1。パフォーマンスとスケーラビリティ:JavaとSpringbootが選択され、大規模なデータと高い同時リクエストを効率的に処理します。 2。開発効率とエコシステム:Reactを使用して、フロントエンド開発効率を向上させ、その豊富なエコシステムを利用します。 3.技術的な負債とメンテナンスコスト:node.jsを選択してマイクロサービスを構築して、メンテナンスコストと技術的債務を削減します。

Netflixのフロントエンドの反応、Vue、および未来Netflixのフロントエンドの反応、Vue、および未来Apr 12, 2025 am 12:12 AM

Netflixは、主にReactをフロントエンドフレームワークとして使用し、特定の機能のためにVUEによって補足されます。 1)Reactのコンポーネント化と仮想DOMは、Netflixアプリケーションのパフォーマンスと開発効率を向上させます。 2)VueはNetflixの内部ツールと小規模プロジェクトで使用されており、その柔軟性と使いやすさが重要です。

フロントエンドのvue.js:実際のアプリケーションと例フロントエンドのvue.js:実際のアプリケーションと例Apr 11, 2025 am 12:12 AM

Vue.jsは、複雑なユーザーインターフェイスを構築するのに適した進歩的なJavaScriptフレームワークです。 1)そのコア概念には、レスポンシブデータ、コンポーネント、仮想DOMが含まれます。 2)実際のアプリケーションでは、TODOアプリケーションを構築し、Vuerouterを統合することで実証できます。 3)デバッグするときは、vuedevtools and Console.logを使用することをお勧めします。 4)パフォーマンスの最適化は、V-IF/V-Show、リストレンダリング最適化、コンポーネントの非同期負荷などを通じて達成できます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター