Vue3のサンドボックスの仕組みの詳しい説明

Vue3のサンドボックスの仕組みの詳しい説明

序文

vue3サンドボックスには主に2つの種類があります

  1. ブラウザでコンパイルされたバージョンは、with構文とプロキシインターセプションを使用します。
  2. ローカルのプリコンパイル済みバージョンでは、テンプレートのプリコンパイル フェーズ中に transformExpression プラグインを使用して、非ホワイトリスト識別子をコンポーネント プロキシ オブジェクトの下に配置します。

ブラウザコンパイル版

レンダリング関数のコンパイル結果

<div>{{テスト}}</div>
<div>{{Math.floor(1)}}</div>

Vue を継承します。

関数 render(_ctx, _cache, $props, $setup, $data, $options) を返します {
  (_ctx) で{
    定数{
      表示文字列: _表示文字列、
      作成VNode: _createVNode、
      フラグメント: _Fragment、
      オープンブロック: _openBlock,
      ブロックの作成: _createBlock、
    } = _Vue;

    戻る (
      _openBlock(),
      _createブロック(
        _断片、
        ヌル、
        [
          _createVNode("div", null, _toDisplayString(test), 1 /* テキスト */),
          _createVNode(
            "div",
            ヌル、
            _toDisplayString(Math.floor(1))、
            1 /* テキスト */
          )、
        ]、
        64 /* 安定フラグメント */
      )
    );
  }
};

上記のコードから、変数識別子にプレフィックスが追加されておらず、スコープ チェーンを拡張するために with 構文でラップされているだけであることがわかります。では、js サンドボックス インターセプションはどのように実現されるのでしょうか。たとえば、変数 test です。理論的には、現在のスコープ チェーンには test 変数はありません。変数は、グローバル スコープが見つかるまで、前のスコープから検索されます。ただし、実際には、_ctx でのみ検索されます。原理は非常に単純です。_ctx はプロキシ オブジェクトです。では、Proxy を使用してインターセプトするにはどうすればよいでしょうか。サンプル コードは次のとおりです。

定数 GLOBALS_WHITE_LISTED =
  「無限大、未定義、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI」+
  「decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array」+
  "オブジェクト、ブール値、文字列、正規表現、マップ、セット、JSON、Intl、BigInt";

const isGloballyWhitelisted = (キー) => {
  GLOBALS_WHITE_LISTED.split(",").includes(key); を返します。
};

const hasOwn = (obj, キー) => {
  Object.prototype.hasOwnProperty.call(obj, key) を返します。
};

定数 origin = {};
const _ctx = 新しいプロキシ(origin, {
  get(ターゲット、キー、受信者) {
    if (hasOwn(ターゲット、キー)) {
      Reflect.get(ターゲット、キー、レシーバー);
    } それ以外 {
      コンソール.警告(
        `レンダリング中にプロパティ ${JSON.stringify(key)} がアクセスされました ` +
          `ただし、インスタンスでは定義されていません。`
      );
    }
  },
  has(ターゲット, キー) {
    // グローバル オブジェクトの場合は false を返し、get インターセプションをトリガーせず、前のスコープから変数を検索します。// グローバル オブジェクトでない場合は true を返し、get インターセプションをトリガーします。 return !isGloballyWhitelisted(key);
  },
});

コードは非常にシンプルですが、なぜこのようなシンプルなコードで傍受が実現できるのでしょうか? with ステートメントは has インターセプションをトリガーするため、has が true を返すと、プロキシ オブジェクトの get インターセプションがトリガーされます。false を返すと、プロキシ オブジェクトの get インターセプションはトリガーされず、変数は現在のプロキシ オブジェクトで検索されず、上位スコープで直接検索されます。

ローカルプリコンパイルバージョン

<div>{{テスト}}</div>
<div>{{Math.floor(1)}}</div>

輸入 {
  toDisplayString を _toDisplayString として、
  createVNode を _createVNode として、
  フラグメントとしての_Fragment、
  openBlock を _openBlock として、
  createBlock を _createBlock として、
} から "vue" へ;

エクスポート関数 render(_ctx, _cache, $props, $setup, $data, $options) {
  戻る (
    _openBlock(),
    _createブロック(
      _断片、
      ヌル、
      [
        _createVNode("div", null, _toDisplayString(_ctx.a), 1 /* テキスト */),
        _createVNode(
          "div",
          ヌル、
          _toDisplayString(Math.floor(1))、
          1 /* テキスト */
        )、
      ]、
      64 /* 安定フラグメント */
    )
  );
}

上記のコードから、ホワイトリストに含まれない識別子には _ctx 変数がプレフィックスとして付けられていることがわかります。では、これはどのように行われるのでしょうか?テンプレートをローカルでコンパイルすると、変換フェーズ中に変数式ノード NodeTypes.SIMPLE_EXPRESSION がプレフィックスとして付加されます。サンプル コードは次のとおりです。

定数 GLOBALS_WHITE_LISTED =
  「無限大、未定義、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI」+
  「decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array」+
  "オブジェクト、ブール値、文字列、正規表現、マップ、セット、JSON、Intl、BigInt";

const isGloballyWhitelisted = (キー) => {
  GLOBALS_WHITE_LISTED.split(",").includes(key); を返します。
};
const isLiteralWhitelisted = (キー)=>{
  'true,false,null,this'.split(',').includes(key) を返します。
}
エクスポート関数 processExpression(
  ノード
){
  const rewriteIdentifier = (raw) => {
    `_ctx.${raw}` を返す
  }
  定数rawExp = ノード.content
  if (isSimpleIdentifier(rawExp)) {
    const isAllowedGlobal = isGloballyWhitelisted(rawExp)
    定数 isLiteral = isLiteralWhitelisted(rawExp)
    if (!isAllowedGlobal && !isLiteral) {
      ノードのコンテンツ = rewriteIdentifier(rawExp)
    }
    戻りノード
  }

もちろん、上記のコードは簡略化されたバージョンにすぎません。元のプラグインでは、__props $setup を正確にしたり、変数クエリパスを短縮したり、パフォーマンスを向上させたり、矢印関数などの複雑な式を babel 経由でコンパイルしたりもしています。

要約する

vue3 js サンドボックスのメカニズム全体が説明されています。ブラウザーでコンパイルされたバージョンは、ステートメント変数クエリでインターセプトできることを知らなかったため、長い間私を悩ませていました。

以上がvue3のサンドボックスの仕組みの詳しい説明です。vue3のサンドボックスの仕組みについてさらに詳しく知りたい方は、123WORDPRESS.COM内の他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • springboot+vue+ドッキング Alipay インターフェース+QR コードスキャン決済機能 (サンドボックス環境)
  • Vue は複数の方法で js ファイルを参照します (推奨)
  • Vueルーティングジャンプの4つの方法の詳細な説明(パラメータ付き)
  • Vue の親コンポーネントと子コンポーネント間の通信の例 (props、$ref、$emit)
  • Vue props の使い方の詳しい説明(要約)
  • Vue プロジェクトで現在のページを更新する 3 つの方法
  • Vue の Props 属性の簡単な理解
  • VUE 要素の非表示と表示 (v-show ディレクティブ)
  • Vueはファイルアップロード機能を実装します
  • Vueを使用して写真をアップロードする3つの方法
  • 一般的な Vue.js 命令の概要 (v-if、v-for など)

<<:  英語の単語の出現頻度を数えるtrコマンドの魔法

>>:  MySQL で浮動小数点データを文字データに変換するときに起こりうる問題の詳細な説明

推薦する

MySQLにおけるSQLの実行順序についてのちょっとした質問

今日、仕事中に左結合に関するSQLの問題に遭遇しました。後で解決しましたが、この問題を通じてSQLの...

主要ブラウザとそのカーネルの紹介

トライデント コア: IE、MaxThon、TT、The World、360、Sogou Brows...

DockerでGDBを使用するときにブレークポイントを入力できない問題を解決する

質問docker で gdb を実行すると、ブレークポイントに到達しますが、ブレークポイントに入るこ...

複数のドメイン名、ポート、IP仮想ホストに基づくNginx構成

1. タイプの導入1.1 ドメインベースの仮想ホスティングいわゆるドメイン名ベースの仮想ホストとは、...

Vue ドラッグ アンド ドロップのシンプルな実装

この記事では、主に次のような Vue ドラッグ アンド ドロップの簡単な実装を紹介します。レンダリン...

Nginx に React プロジェクトをデプロイする方法の例

テストプロジェクト: react-demo react-demo プロジェクトをサーバーにクローンし...

Alibaba Cloud で MySQL リモート接続を構成するための詳細な手順

序文ご存知のとおり、デフォルトでは、Alibaba Cloud にインストールされている MySQL...

Bootstrap 3.0 学習ノートのボタンとドロップダウン メニュー

前回の記事はBootstrap CSS部分の簡単なレビューであり、多くの詳細が見落とされていました。...

Vue3のレスポンシブ原則の詳細な説明

目次Vue2 レスポンシブ原則のレビューVue3 レスポンシブ原則の分析ネストされたオブジェクトの応...

mysql8.0.11をインストールしてrootパスワードを変更し、navicat for mysqlに接続するアイデアの詳細な説明

1.1. ダウンロード:公式ウェブサイトから zip パッケージをダウンロードします。私は 64 ビ...

Win10環境にMysql5.7.23をインストールする際の問題点と落とし穴

たくさんのチュートリアルを読みましたが、うまくインストールできませんでした。しばらく試行錯誤した後、...

MySQLの自己接続と結合の詳細な理解

1. MySQL 自己接続MySQL では、情報を照会するときに自分自身に接続 (自己接続) する必...

Vueのdiffアルゴリズムについての簡単な説明

目次概要バーチャルドム原理実装プロセスパッチ方式sameVnode関数patchVnode関数upd...

抽選効果を実現するJavaScript

この記事では、宝くじマシンの効果を実現するためのJavaScriptの具体的なコードを参考までに共有...

WeChat アプレット開発フォーム検証 WxValidate の使用

個人的には、WeChat アプレットの開発フレームワークは VUE と概ね似ていると感じていますが、...