シンプルで簡単な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 タグの右上隅に削除アイコンを追加するサンプルコード

推薦する

vue+drf+サードパーティのスライディング検証コードアクセスの実装

目次1. 背景2. 検証プロセス3. 検証を作成する4. フロントエンドコード4.1 コアjsファイ...

Win10 での MySQL 8.0 ログインでユーザー 'root'@'localhost' のアクセスが拒否される (パスワード使用: YES) 問題の解決方法

最近、MySQL を学び始めました。インストールはスムーズに進み、インターネット上の既成のチュートリ...

ViteでReactプロジェクトを構築する方法

目次序文Viteプロジェクトを作成する改修プロジェクトディレクトリの規則その他の構成序文毎日鳩、火ば...

MySQL で 2 つのデータベース テーブル構造を比較する方法

開発およびデバッグのプロセスでは、新しいコードと古いコードの違いを比較する必要があります。比較には、...

opensslを使用して無料の証明書を生成する方法

1: openssl とは何ですか? その機能は何ですか?適用シナリオは何ですか? Baidu 百科...

Ubuntu 18.04 での Pycharm インストール チュートリアルの実装

方法1: Pycharmをダウンロードしてインストールするダウンロードアドレス: https://w...

MySQL の 2 種類の一時テーブルの使用方法の詳細な説明

外部一時テーブルCREATE TEMPORARY TABLE によって作成された一時テーブルは、外部...

Linux MySQL ルートパスワードを忘れた場合の解決方法

MySQL データベースを使用する際、何らかの理由で長期間 MySQL にログインしていない場合、ま...

jar パッケージを Docker コンテナに変換する方法

jar パッケージを Docker コンテナに変換する方法1.まずJavaイメージをダウンロードする...

Vue ページをリフレッシュするために provide と injection を適用する

目次方法1: 関数を直接呼び出す方法2: provide / inject (静的更新) を使用する...

vue keep-alive の簡単な概要

1. 機能主にコンポーネントの状態を保持したり、再レンダリングを回避したりするために使用されます。 ...

Apache Flink の任意の Jar パッケージのアップロードにより、リモート コード実行の脆弱性が再発する問題が発生する (脆弱性警告)

脆弱性の説明Apache Flink は、分散ストリームおよびバッチ データ処理用のオープン ソース...

複数の値を返す MySQL ストアド プロシージャ メソッドの例

この記事では、例を使用して、MySQL ストアド プロシージャで複数の値を返す方法について説明します...

CSSは親要素の下の最初の子要素を選択します(:first-child)

序文最近、プロジェクトで :first-child を使用したのですが、すぐに思いつきました。これは...

CSS3 で画像ドロワー効果を実装するためのサンプル コード

いつものように、まずは画像効果を投稿しましょう: このエフェクトの原理は非常にシンプルです。CSS3...