シンプルで簡単なJavaScript開発のためのSvelte実装原理の詳細な説明

シンプルで簡単なJavaScript開発のためのSvelte実装原理の詳細な説明

Svelte は長い間存在しており、私はいつもわかりやすい原理分析記事を書きたいと思っていました。長い間先延ばしにしていましたが、ついにそれを書きました。

デモ1

まず、コンパイル プロセスを見てみましょう。次のAppコンポーネント コードを検討してください。

<h1>{カウント}</h1>
<スクリプト>
  count = 0 とします。
</スクリプト>

このコードはコンパイラによってコンパイルされると、次の 3 つの部分で構成されるコードを生成します。

create_fragmentメソッド

countステートメント

class Appの宣言文

// 一部のコードを省略します...
関数create_fragment(ctx) {
  h1とします。 
  戻る {
    c() {
      h1 = 要素("h1");
      h1.textContent = `${count}`;
    },
    m(ターゲット, アンカー) {
      挿入(ターゲット、h1、アンカー);
    },
    d(切り離し) {
      if (デタッチ) detach(h1);
    }
  };
} 
count = 0 とします。 
クラスAppはSvelteComponentを拡張します{
  コンストラクタ(オプション) {
    素晴らしい();
    init(this、オプション、null、create_fragment、safe_not_equal、{});
  }
} 
デフォルトのアプリをエクスポートします。

フラグメントの作成

まず、 App UIに基づいてコンパイラによってコンパイルされ、コンポーネントがブラウザと対話するためのメソッドを提供するcreate_fragmentメソッドを見てみましょう。上記のコンパイル結果には、次の 3 つのメソッドが含まれています。

c createの略で、テンプレートの内容に従って対応するDOM Elementを作成するために使用されます。この例では、 H1に対応するDOM Elementを作成します。

h1 = 要素("h1");
h1.textContent = `${count}`;

m mountの略で、 cによって作成されたDOM Elementページに挿入し、コンポーネントの最初のレンダリングを完了するために使用されます。この例では、 H1ページに挿入されます。

挿入(ターゲット、h1、アンカー);

insertメソッドはtarget.insertBeforeを呼び出します。

関数挿入(ターゲット、ノード、アンカー) {
  target.insertBefore(ノード、アンカー || null);
}

d detachの略で、コンポーネントの対応するDOM Elementページから削除するために使用されます。この例では、 H1が削除されます。

if (デタッチ) detach(h1);

detachメソッドはparentNode.removeChild呼び出します。

関数 detach(ノード) {
  ノードの親ノードを削除します。
}

フローチャートをよく見ると、 Appコンポーネントのコンパイル済み製品には、図のfragment内のpメソッドがないことがわかります。

これは、 App状態を変更するためのロジックがないため、対応するメソッドがコンパイルされた製品に表示されないためです。

create_fragmentによって返されるcメソッドとmメソッドは、コンポーネントの最初のレンダリングに使用されていることがわかります。では、これらのメソッドを呼び出すのは誰でしょうか?

スヴェルトコンポーネント

各コンポーネントは、 SvelteComponentから継承するclassに対応しています。インスタンス化されると、 initメソッドが呼び出され、コンポーネントの初期化が完了します。 create_fragment initで呼び出されます。

クラスAppはSvelteComponentを拡張します{
  コンストラクタ(オプション) {
    素晴らしい();
    init(this、オプション、null、create_fragment、safe_not_equal、{});
  }
}

要約すると、 Demo1のフローチャートの点線部分のコンパイル結果は次のようになります。

fragment : create_fragmentメソッドの戻り値としてコンパイルされます

UI : create_fragment戻り値におけるmメソッドの実行結果

ctx : コンポーネントのコンテキストを表します。この例には変化しない状態count 1 つだけ含まれているため、 ctx count

状態を変更できるデモ

ここで、 Demo変更し、 updateメソッドを追加し、クリック イベントをH1にバインドし、クリック後のcount変更します。

<h1 on:click="{update}">{count}</h1> 
<スクリプト>
  count = 0 とします。
  関数 update() {
    カウント++;
  }
</スクリプト>

コンパイルされた製品の変更、およびctxの変更は次のとおりです。

// モジュールのトップレベルの宣言から let count = 0; 
// インスタンスメソッドになる function instance($$self, $$props, $$invalidate) {
  count = 0 とします。 
  関数 update() {
    $$ 無効化(0, count++, count);
  } 
  [count, update]を返します。
}

countmoduleの最上位レベルの宣言ステートメントからinstanceメソッド内の変数に変更されます。この変更の理由は、 App複数のインスタンスを作成できるためです。

// テンプレートに3つのアプリを定義する
<アプリ/>
<アプリ/>
<アプリ/>
// count が不変の場合、ページは次のようにレンダリングされます: <h1>0</h1>
<h1>0</h1>
<h1>0</h1>

countが不変の場合、すべてのApp同じcountを再利用できます。ただし、 countが可変の場合、さまざまなAppがクリックされた回数に応じて、ページは次のようにレンダリングされる可能性があります。

<h1>0</h1>
<h1>3</h1>
<h1>1</h1>

したがって、各App count保存するために独立したコンテキストを持つ必要があり、これがinstanceメソッドの意味です。一般的に、 Svelteコンパイラは<script>内のすべての変数宣言を追跡します。

  • count++などの変数を変更するステートメントが含まれていますか?
  • count = 1などの再代入文が含まれているかどうか
  • 状況を待つ

見つかった変数はinstanceに抽出され、 instanceの実行後の戻り値はコンポーネントに対応するctxになります。

同時に、上記の操作を実行するステートメントがテンプレートを通じて参照できる場合、そのステートメントは$$invalidateでラップされます。

Demo2では、 updateメソッドは次を満たします。

  • countを変更するステートメントが含まれています - count++
  • テンプレートを通じて参照可能 - クリックコールバック関数として

したがって、コンパイルされたupdateでの変更countのステートメントは$$invalidateメソッドによってラップされます。

// ソースコードの更新
関数 update() {
  カウント++;
} 
// コンパイルされたインスタンスで更新
関数 update() {
  $$ 無効化(0, count++, count);
}
  • Demo2count++など、 ctxに保存された状態の値を更新します。
  • dirtyマーク、つまり、変更されるApp UIcount関連部分をすべてマークします。
  • 更新をスケジュールします。この更新をmicrotaskでスケジュールします。同じmacrotaskで実行されるすべての$$invalidatemacrotaskが完了した後に均一に実行され、最後にコンポーネントfragmentpメソッドが実行されます。

pメソッドはDemo2の新しいコンパイル製品です。 pに加えて、 create_fragmentの既存のメソッドも対応する変更を受けます。

c() {
  h1 = 要素("h1");
  //countの値はctxから取得されます t = text(/*count*/ ctx[0]);
},
m(ターゲット, アンカー) {
  挿入(ターゲット、h1、アンカー);
  追加(h1, t);
  // イベントバインディング dispose = listen(h1, "click", /*update*/ ctx[1]);
},
p(ctx, [ダーティ]) {
  // set_data は t に格納されているテキスト ノードを更新します。if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);
},
d(切り離し) {
  if (デタッチ) detach(h1);
  // イベントのバインド解除 dispose();
}

pメソッドは、 $$invalidatedirtyとしてマークされた項目に対応する更新関数を実行します。

Demo2では、 App UIで参照されるのは状態countのみなので、 updateメソッドにはifステートメントが 1 つだけあります。 UIで複数の状態が参照される場合は、 pメソッドにも複数のifステートメントが含まれます。

// UI 内の複数の状態を参照する<h1 on:click="{count0++}">{count0}</h1>
<h1 on:click="{count1++}">{count1}</h1>
<h1 on:click="{count2++}">{count2}</h1>

対応するpメソッドには複数のifステートメントが含まれています。

p(new_ctx, [ダーティ]) {
  ctx = new_ctx;
  if (dirty & /*count*/ 1) set_data(t0, /*count*/ ctx[0]);
  if (dirty & /*count1*/ 2) set_data(t2, /*count1*/ ctx[1]);
  if (dirty & /*count2*/ 4) set_data(t4, /*count2*/ ctx[2]);
},

Demo2完全な更新手順は次のとおりです。

  1. H1をクリックするとコールバック関数のupdateトリガーされます
  2. update$$invalidate呼び出し、 ctxcountを更新し、 countdirtyとしてマークし、 update をスケジュールします。
  3. pメソッドを実行し、 if文に対応するdirtyアイテム( count )を入力し、メソッドを実行して対応するDOM Element更新する

上記は、JavaScript 開発における Svelte の実装原則の詳細な説明の詳細な内容です。Svelte の実装原則の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Svelte の Defer Transition を Vue で実装する方法
  • アニメーション効果のようなVueトランジションの例
  • Vue トランジション効果の CSS トランジションの詳細説明 (transition、animation、animate.css との組み合わせ)
  • Vueで再利用可能なトランジションを作成する方法

<<:  MySQL移行計画と落とし穴の実践記録

>>:  HTML+CSS で div タグの右上隅に削除アイコンを追加するサンプルコード

推薦する

MySQL無料インストールバージョンの設定チュートリアル

この記事では、参考までにMySQLの無料インストール構成チュートリアルを紹介します。具体的な内容は次...

CSS3 パッケージ化後にプレフィックスプラグインを自動的に追加する方法の詳細な説明: autoprefixer

vue-cli で構築されたプロジェクト スキャフォールディングでは、すでに autoprefix...

Docker初心者が初めてよく使うコマンドを試してみる練習記録

Docker を正式に使用する前に、まず Docker でよく使用されるコマンドに慣れておきましょう...

jsを使用して簡単な抽選機能を実現する

この記事では、参考までに、簡単な抽選機能を実装するためのjsの具体的なコードを共有します。具体的な内...

要素 el-button ボタンコンポーネントの使用の詳細な説明

1. 背景ボタンは非常によく使われており、Element のボタン機能は非常に包括的です。この記事で...

WeChat アプレット学習 WXS 使用方法チュートリアル

wxsとは何ですか? wxs (WeiXin Script) は、小規模プログラム用のスクリプト言語...

中国語ウェブコンテンツを紹介する10の経験

<br /> テキスト、シンボル、リンクの 3 つの側面に焦点を当て、主に中国語で、私の...

Docker+K8S+GitLab/SVN+Jenkins+Harbor をベースにした継続的インテグレーション配信環境の構築に関する詳細なチュートリアル

目次環境設定の概要1.K8Sとは何ですか? 2. K8S を使用する理由3. K8S を使用する利点...

Nginx のパラメータをオンにして Web パフォーマンスを 3 倍向上させる方法

1. 遭遇したいくつかの問題2008 年にパフォーマンス テストを行っていたとき、パフォーマンス テ...

1 つの記事で Nginx の現在の制限を理解する (簡単な実装)

Nginx は現在、最も人気のあるロード バランサーの 1 つです。インターネット トラフィックの...

MySQL コマンドライン操作中のエンコードの問題の詳細な説明

1. MySQLデータベースのエンコーディングを確認する mysql -u ユーザー名 -p パスワ...

Dockerコンテナの個別展開のためのLNMPの実装

1. 環境整備各コンテナの IP アドレス: nginx: 172.16.10.10マイSQL: 1...

RabbitMQ の Docker インストールと設定手順

目次単一マシンの展開オンラインプルミラーを見るRabbitMQを作成して実行するMQコンテナを正常に...

MySQLトリガートリガー例の詳細な説明

目次トリガーとは何かトリガーを作成する表は次のようになります。さらにいくつかの単語を挙げます。制限と...

WeChatアプレットが弾丸画面を送信するビデオプレーヤーを実装

この記事では、WeChatアプレットでビデオプレーヤーの集中砲火を実装するための具体的なコードを参考...