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

推薦する

vue3ソースコード解析の簡単な実装方法

目次序文🍹準備🍲vue3 の使い方🍖 実装要約する序文最近、私の最初の公式 vue3 + ts プロ...

Linux での syslogd および syslog.conf ファイルの解釈

1: syslog.conf の概要異なるタイプの Unix の場合、標準の UnixLog システ...

Linux カーネルの copy_{to, from}_user() に関する考察

目次1. copy_{to,from}_user() とは何か1. copy_{to,from}_u...

HTMLテキストオーバーフローの2つの一般的な解決策は省略記号を表示することです

方法1: CSSオーバーフロー省略を使用して解決する解決策は次のとおりです。 CSSコード: ディス...

MySQL マスター スレーブ データが矛盾しています。プロンプト: Slave_SQL_Running: 解決策はありません

この記事では、MySQL マスターとスレーブ データ間の不一致の解決方法と、プロンプト「Slave_...

Docker ベースの Tomcat クラスタと Nginx ロード バランシングの展開の概要

目次前面に書かれた1. Ngixnイメージの作成2. Java Web (Tomcat) アプリケー...

CentOS8 yum/dnfで国内ソースを設定する方法

CentOS 8 ではソフトウェア パッケージのインストール プログラムが変更され、yum 構成方法...

Zabbix が MySQL のマスター/スレーブ状態を監視する方法の詳細な説明

MySQLマスタースレーブを設定した後、スレーブの状態が正常かどうかわからないことが多く、例外が発生...

Flutterを使用して移動可能なスタックウィジェット機能を作成する

この投稿では、キャンバスとドラッグ可能なノード インターフェースを使用するデスクトップおよび Web...

HTML テーブルタグチュートリアル (12): 境界線スタイル属性 FRAME

FRAME プロパティを使用して、表の境界線のスタイル タイプを制御します。基本的な構文<T...

Windows で Graphviz をインストールして開始する方法のチュートリアル

ダウンロードとインストール環境変数の設定インストール環境変数の設定確認基本的な描画の紹介グラフディグ...

Linux サーバー上で nvidia-docker 環境を設定するプロセスの詳細な説明

Docker はコンテナに相当し、必要な動作環境に応じて対応する動作環境を構築できます。このとき、各...

ドロップダウンメニューとスライドメニューのデザイン例

ドロップダウン メニューやスライド メニューを使用している Web サイトをたくさん見つけたので、私...

Windows 環境での MySQL 8.0 のインストール、設定、アンインストール

ソフトウェアバージョンウィンドウズ: ウィンドウズ10 MySQL: mysql-8.0.17-wi...

Vueはプルダウンを実装してさらに読み込む

Element-UI に慣れた開発者なら、無限スクロールの InfiniteScroll が使いにく...